Description
As a:
...I need to be able to:
Aggregate config properties in beans with non-trivial constructors in particular record classes.
More generally, I want to remove all restriction @ConfigProperties beans. They should just be (almost) normal class beans and support every CDI feature like interception & decoration, non-trivial bean constructors, PostConstruct & @PreDestroy methods...
Currently, the smallrye implementation imposes some (unspecified) restrictions, e.g. @ConfigProperties beans cannot have @PostConstruct methods or producer methods, because smallrye vetoes the original and adds a synthetic bean which loses everything but the information about field injection points.
...which enables me to:
a.) write more concise code with records, because it is no longer necessary to have injection point fields and write getter for all of them. Everything could in principle be done in the canonical constructor of a record if only I were able to write (taking the example from the spec)
@ConfigProperties(prefix="server")
@Dependent
public record Details(String host,
int port,
String endpoint,
@ConfigProperty(name="old.location") String location) {}
This can work for records, but not other classes, because the names of the parameters of the canonical constructor are always retained in the class file as the names of the record components. So the problem that constructor- and method-parameter names need not be present for reflection, does not appear with records.
Records also have the nice benefit that they provide a canonical place to do validation of the aggregated properties.
b.) do non-trivial validation in @PostConstruct, e.g.
@ConfigProperties(prefix="my.app")
@Dependent
class Range {
int from;
int to;
@PostConstruct
void validate(){
if (from > to){
throw new IllegalStateException("Non-sensical config values");
}
}
}
or again stealing from the example in the spec:
@ConfigProperties(prefix="server")
@Dependent
public class Details {
public String host; // the value of the configuration property server.host
public int port; // the value of the configuration property server.port
private String endpoint; //the value of the configuration property server.endpoint
public @ConfigProperty(name="old.location")
String location; //the value of the configuration property server.old.location
@PostConstruct
void validate(){
if (port <= 0) {
throw new IllegalStateExeption("Check the config. Some idiot configured negative ports");
}
}
}
Some obvious validations like this one can be done with the smallrye implementation by using Jakarta Bean Validation's @Min annotation, but for something like the Range example that needs to correlate multiple config properties, a single annotation is not sufficient, but writing a custom Validator seems like overkill. Also it's certainly a non-trivial leap for a developer to use Bean Validation.
c.) support computed default values, e.g.
@ConfigProperties(prefix="my.app")
@Dependent
class Server {
@ConfigProperty(defaultValue="localhost")
String host;
@ConfigProperty(defaultValue="8080")
int basePort;
@ConfigProperty(defaultValue="0")
int portShift;
@ConfigProperty(defaultValue="-1")
int port1;
@ConfigProperty(defaultValue="-1")
int port2;
@ConfigProperty(defaultValue="-1")
int port3;
@PostConstruct
void calculatedDefaults(){
if (port1 < 0){
port1 = basePort + portShift + 1;
}
if (port2 < 0){
port2 = basePort + portShift + 3;
}
if (port3 < 0){
port3 = basePort + portShift + 3;
}
}
}
At the moment this would need to be done in custom getter methods for example.
d.) use producer methods directly in @ConfigProperties to provide simplified/transformed views of the config, e.g.
@ConfigProperties(prefix="my.app")
@Dependent
class Dates {
@ConfigProperty(defaultValue="1970-01-01")
LocalDate date;
LocalTime time;
@Produces
@Dependent
CustomDateFormat custom(){
return new CustomDateFormat(date.getYear(), date.getMonthValue(), date.getDayOfMonth());
}
}
record CustomDateFormat(int year, int month, int day){}
At the moment, this does not work with smallrye, because of how @ConfigProperties is implemented. One needs a separate bean class for the producer methods.
Implementation details
The requirement of a no-args constructor seems like an implementation detail to me. It took some fiddling, but I have a proof of concept that shows that this detail is not necessary and one can in fact integrate with a CDI container without relying on this restriction.
Description
As a:
...I need to be able to:
Aggregate config properties in beans with non-trivial constructors in particular record classes.
More generally, I want to remove all restriction
@ConfigPropertiesbeans. They should just be (almost) normal class beans and support every CDI feature like interception & decoration, non-trivial bean constructors,PostConstruct&@PreDestroymethods...Currently, the smallrye implementation imposes some (unspecified) restrictions, e.g.
@ConfigPropertiesbeans cannot have@PostConstructmethods or producer methods, because smallrye vetoes the original and adds a synthetic bean which loses everything but the information about field injection points....which enables me to:
a.) write more concise code with records, because it is no longer necessary to have injection point fields and write getter for all of them. Everything could in principle be done in the canonical constructor of a record if only I were able to write (taking the example from the spec)
This can work for records, but not other classes, because the names of the parameters of the canonical constructor are always retained in the class file as the names of the record components. So the problem that constructor- and method-parameter names need not be present for reflection, does not appear with records.
Records also have the nice benefit that they provide a canonical place to do validation of the aggregated properties.
b.) do non-trivial validation in
@PostConstruct, e.g.or again stealing from the example in the spec:
Some obvious validations like this one can be done with the smallrye implementation by using Jakarta Bean Validation's
@Minannotation, but for something like theRangeexample that needs to correlate multiple config properties, a single annotation is not sufficient, but writing a custom Validator seems like overkill. Also it's certainly a non-trivial leap for a developer to use Bean Validation.c.) support computed default values, e.g.
At the moment this would need to be done in custom getter methods for example.
d.) use producer methods directly in
@ConfigPropertiesto provide simplified/transformed views of the config, e.g.At the moment, this does not work with smallrye, because of how
@ConfigPropertiesis implemented. One needs a separate bean class for the producer methods.Implementation details
The requirement of a no-args constructor seems like an implementation detail to me. It took some fiddling, but I have a proof of concept that shows that this detail is not necessary and one can in fact integrate with a CDI container without relying on this restriction.