英文:
org immutables - no default constructor on abstract class
问题
使用https://immutables.github.io/,我想知道是否有可能创建一个类似于自定义不可变抽象类,继承自没有默认构造函数的类。在这个示例中,它是Spring的ApplicationEvent的子类(并且还利用了构建器功能):
@Value.Immutable
@Value.Style(
privateNoargConstructor = true,
get = {"is*", "get*"},
init = "set*",
passAnnotations = Builder.class)
public abstract class CustomEvent extends ApplicationEvent {
//... 这里我需要构造函数!
abstract String getFoo();
}
如果抽象类没有默认构造函数,您可以如何完成这个任务?
public abstract class ApplicationEvent extends EventObject {
...
public ApplicationEvent(Object source) {
super(source);
...
}
}
编辑:
如果我创建一个匹配的构造函数,如下所示:
private CustomEvent(Object source) {
super(source);
}
我会得到一个"生成的" ImmutableCustomEvent 构造函数,像这样:
private ImmutableCustomEvent() {
this.foo = null;
}
这是有道理的,因为它尝试生成一个具有所有必要"属性"的类,但不考虑"唯一可用"的构造函数。
编辑2:
我期望生成的构造函数如下:
private ImmutableCustomEvent() {
super(null);
this.foo = null;
}
或至少是这样:
private ImmutableCustomEvent(Object source) {
super(source);
this.foo = null;
}
英文:
Using https://immutables.github.io/ I wonder if it is possible to have something like custom immutable abstract class inheriting from a class without a default constructor. In this example a sub of Spring's ApplicationEvent (and also take advantage of builder functionality):
@Value.Immutable
@Value.Style(
privateNoargConstructor = true,
get = {"is*", "get*"},
init = "set*",
passAnnotations = Builder.class)
public abstract class CustomEvent extends ApplicationEvent {
//... I need constructor here!
abstract String getFoo();
}
How would you accomplish this if you have no default constructor on the abstract class?
public abstract class ApplicationEvent extends EventObject {
...
public ApplicationEvent(Object source) {
super(source);
...
}
}
EDIT:
If I create a matching constructor like:
private CustomEvent(Object source) {
super(source);
}
I will get a "generated" ImmutableCustomEvent constructor like this:
private ImmutableCustomEvent() {
this.foo = null;
}
Which makes sense, as it tries to generate a class with all the "properties" necessary, but does not consider the "only available" constructor
EDIT2:
What I expect as a generated constructor
private ImmutableCustomEvent() {
super(null)
this.foo = null;
}
or at least
private ImmutableCustomEvent(Object source) {
super(source)
this.foo = null;
}
答案1
得分: 2
以下是已翻译的内容:
"So it appears that immutables does not currently generate constructors with super calls, like you need to subclass ApplicationEvent in spring, as you need "a constructor matching super"."
"因此,看起来 immmutables 目前不会生成带有 super 调用的构造函数,就像您需要在 Spring 中对 ApplicationEvent 进行子类化一样,您需要一个“匹配 super 的构造函数”."
"As you can see here, the constructor template goes from the javadoc for the constructor straight into enumerating arguments. the Invokable class being referenced here is from guava (30.0 on the latest immutables) represents a method signature."
"正如您可以在这里看到的,构造函数模板直接从构造函数的 javadoc 进入枚举参数。这里引用的Invokable类来自 guava(最新的 immutables 版本是 30.0),表示方法签名。"
"I believe that this line is some kind of hook into the immutables templating system (that would need to be expanded to support generating super constructor calls). As you can see it appears right after the opening curly brace of the constructor (and an if statement that decides to generate that constructor."
"我相信这一行是 immutables 模板系统的某种钩子(需要扩展以支持生成 super 构造函数调用)。正如您可以看到,它出现在构造函数的左花括号之后(以及一个 if 语句,决定是否生成该构造函数)."
"The templating system is complicated, and it might be discontinued in the future. But it seems they are receptive to feedback about redesigning extensibility for new use cases."
"模板系统很复杂,将来可能会停用。但似乎他们愿意接受关于重新设计新用例的可扩展性的反馈。"
[if type.factoryOf.new]
/**
* Construct a new immutable {@code [type.name]} instance.
[for v in type.constructorArguments]
* @param [v.name] The value for the {@code [v.name]} attribute[if v.nullable], can be {@code null}[/if]
[/for]
*/
[eachLine type.constructorAnnotations]
...
private [type.typeImmutable.simple]([output.linesShortable][for v in type.constructorArguments][if not for.first],[/if]
[v.atNullability][constructorAcceptTypeInvokable v] [v.name][/for][/output.linesShortable]) {
[/if]
[if type.constructorOmited or (type.hasEncodingValueOrVirtualFields or (type.generateSafeDerived and type.hasDerivedAttributes))]
### not sure what this does, but it is the first thing that happens
### when a constructor is generated
[let shim][disambiguateField type 'initShim'][/let]
### probably just need to add something here that considers what supers exist
### then goes right into args
[for v in type.constructorArguments, n = v.name]
...
this.[n] = [valueFrom type v n withoutOptional];
...
[/if]
[generateAfterConstruction type false]
}
[/template]
英文:
So it appears that immutables does not currently generate constructors with super calls, like you need to subclass ApplicationEvent in spring, as you need "a constructor matching super".
As you can see here, the constructor template goes from the javadoc for the constructor straight into enumerating arguments. the Invokable class being referenced here is from guava (30.0 on the latest immutables) represents a method signature.
I believe that this line is some kind of hook into the immutables templating system (that would need to be expanded to support generating super constructor calls). As you can see it appears right after the opening curly brace of the constructor (and an if statement that decides to generate that constructor.
The templating system is complicated, and it might be discontinued in the future. But it seems they are receptive to feedback about redesigning extensibility for new use cases.
[template generateConstructor Type type Boolean withoutOptional Invokable constructorAcceptTypeInvokable]
[if type.factoryOf.new]
/**
* Construct a new immutable {@code [type.name]} instance.
[for v in type.constructorArguments]
* @param [v.name] The value for the {@code [v.name]} attribute[if v.nullable], can be {@code null}[/if]
[/for]
*/
[eachLine type.constructorAnnotations]
...
private [type.typeImmutable.simple]([output.linesShortable][for v in type.constructorArguments][if not for.first],[/if]
[v.atNullability][constructorAcceptTypeInvokable v] [v.name][/for][/output.linesShortable]) {
[/if]
[if type.constructorOmited or (type.hasEncodingValueOrVirtualFields or (type.generateSafeDerived and type.hasDerivedAttributes))]
### not sure what this does, but it is the first thing that happens
### when a constructor is generated
[let shim][disambiguateField type 'initShim'][/let]
### probably just need to add something here that considers what supers exist
### then goes right into args
[for v in type.constructorArguments, n = v.name]
...
this.[n] = [valueFrom type v n withoutOptional];
...
[/if]
[generateAfterConstruction type false]
}
[/template]
答案2
得分: -1
对于不可变类,我建议在(受保护的)构造函数中提供所有字段。请记住,继承类必须能够看到父类的构造函数在范围内。
由于类应该是不可变的,并且您希望确保所有字段都是final(也是不可变的)更安全。
在考虑构建器模式时,提供一个静态子类Builder,其中包括合理的默认值和构建器方法。
从Java 14+开始,还有使用记录(records)的替代选项,参见https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/Record.html,这也可以与构建器结合使用。
英文:
For an immutable class, I would recommend to provide all fields in the (protected) constructor. Keep in mind, the inheriting class must see the parent's constructor in scope.
Since the class shall be immutable, and you want to be sure, it's always safer to have all the fields final (and immutable as well).
When considering the builder-pattern, provide a static sub-class Builder, provide with it the reasonable defaults and builder-methods.
From Java 14+, there is the alternative option to use records, see https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/Record.html
, which also is feasible to be combined with a builder.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论