Is it possible to override the ConsumerFactory's configured deserializers if provided as an object instead of a class name in the properties? Maybe in a ContainerCustomizer?
No; it is not possible - the only way you can provide an object is via the factory constructors or setters before creating a consumer; you cannot override these at all, not even with properties, because they are passed directly to the KafkaConsumer and they will be used instead of any specified in the properties.
See ConsumerConfig.appendDeserializerToConfig().
You would need to use a different consumer factory if you want to override the defaults with objects.
Related
This is the code that I have:
#Component
#Configuration
#PropertySource("application.properties")
public class Program {
#Value("${app.title}")
private String appTitle;
public Program() {
System.out.println(appTitle);
}
}
The application.properties has
app.title=The Program
The output is null insteaf of The Program.
So, what am I missing? I have tried several examples; none worked.
Since appTitle is an autowired field, it is not set until after the object is initially constructed. This is why the value is still null in your example. The bean construction process in this scenario is as follows:
The Program constructor is called, creating a new Program instance
The appTitle field is set on the newly constructed bean to ${app.title}
The ideal fix for this depends on your goals. If you truly need the value within the constructor, you can pass it in as an autowired constructor parameter. The value will then be available within the constructor:
#Component
#Configuration
#PropertySource("application.properties")
public class Program {
public Program(#Value("${app.title}") appTitle) {
System.out.println(appTitle);
}
}
If you don't need it in the constructor itself, but need it for the proper initialization of the bean, you could alternatively use the #javax.annotation.PostConstruct annotation to make use of it after the object's construction but before it is made available for use elsewhere:
#Component
#Configuration
#PropertySource("application.properties")
public class Program {
#Value("${app.title}")
private String appTitle;
#PostConstruct
public void printAppTitle() {
System.out.println(appTitle);
}
}
Finally, if you don't need the value at construction time, but need it during the life of the bean, what you have will work; it just won't be available within the body of the constructor itself:
#Component
#Configuration
#PropertySource("application.properties")
public class Program {
#Value("${app.title}")
private String appTitle;
}
Nothing wrong, just don't do it in a constructor...
Other answers on this question are written assuming the goal is creating a Spring-managed bean that uses the given property in its creation. However, based on your comments in another answer, it looks like the question you want answered is how to access an externalized property (one provided by #Value) within a no-argument constructor. This is based on your expectation that a Java inversion of control (IoC) container such as Spring should allow accessing externalized properties (and presumably other dependencies) within a no-argument constructor. That being the case, this answer will address the specific question of accessing the property within a no-argument constructor.
While there are certainly ways this goal could be achieved, none of them would be idiomatic usage of the Spring framework. As you discovered, autowired fields (i.e. fields initialized using setter injection) cannot be accessed within the constructor.
There are two parts to explaining why this is. First, why does it work the way it does, programmatically? Second, why was it designed the way it was?
The setter-based dependency injection section of the Spring docs addresses the first question:
Setter-based DI is accomplished by the container calling setter methods on your beans after invoking a no-argument constructor or a no-argument static factory method to instantiate your bean.
In this case, it means that first the object is created using the no-argument constructor. Second, once the object is constructed, the appTitle is initialized on the constructed bean. Since the field isn't initialized until after the object is constructed, it will have its default value of null within the constructor.
The second question is why Spring is designed this way, rather than somehow having access to the property within the constructor. The constructor-based or setter-based DI? sidebar within the Spring documentation makes it clear that constructor arguments are in fact the idiomatic approach when dealing with mandatory dependencies in general.
Since you can mix constructor-based and setter-based DI, it is a good rule of thumb to use constructors for mandatory dependencies and setter methods or configuration methods for optional dependencies. [...]
The Spring team generally advocates constructor injection, as it lets you implement application components as immutable objects and ensures that required dependencies are not null. Furthermore, constructor-injected components are always returned to the client (calling) code in a fully initialized state. [...]
Setter injection should primarily only be used for optional dependencies that can be assigned reasonable default values within the class. [...]
A property needed to construct the object certainly would be categorized as a mandatory dependency. Therefore, idiomatic Spring usage would be to pass in this required value in the constructor.
So in summary, trying to access an application property within a no-argument constructor is not supported by the Spring framework, and in fact runs contrary to the recommended use of the framework.
Maybe I'm missing something, but with Java 8 we can have default methods inside an Interface and I`m trying to modify an existing one, adding a new default method that Observes an Event and calls the old method signature at this same Interface, just to avoid code changes in legacy Beans (in this case, all #ApplicationScoped). Ex:
public interface A {
public void oldMehtod(Event evt);
default void newMethod(#Observes Event evt) {
this.oldMehtod(Event evt);
}
}
The "newMethod" is never fired by a Bean that implements this Interface. What I`m missing? Thanks in advance!
From CDI specification, you may want to read more about it then just this quotation:
An observer method is a non-abstract method of a managed bean class or session bean class...
Yours is not a method of a managed bean class. You will need to place that method on an actual bean class to have it discovered.
I cannot tell you exactly why you cannot have them on interfaces but I suppose it's some hard limitation. That would be good question to ask on CDI-dev mailing list.
I have a simple persistent pojo like:
public class Peristent {
private String unsafe;
}
I use Spring Data mongoTemplate to persist and fetch the above object. I also need to encrypt the Persistent.unsafe variable and store a complex representation of that in backend, everytime I try to save Persistent object.
Can I annotate Persistent, or provide some sort of hooks where I can make the aforementioned translations without me having to do that in the Pojo code manually. This has to happen automatically during mongoTemplate.insert.
Spring Data currently only support Type based conversions. There is an issue for supporting property based conversion, which you might want to track.
Therefore annotating won't work. What you could do is, create use a separate class for the property, which just wraps the String and register a custom converter for that type. See http://docs.spring.io/spring-data/data-mongo/docs/1.10.4.RELEASE/reference/html/#mongo.custom-converters for details, how to do that.
We are using a custom DataSource which achieves multi-tenancy. (We have a single DataSource bean which acts like a proxy to other datasources, and the tenant context is set using ThreadLocal variables. My requirement is to get the metrics of the individual datasources proxied by that single DataSource Bean.) Basically, i need to somehow add additional metrics. It seems like the best way would be to extend DataSourcePublicMetrics, since PublicMetricsAutoConfiguration conditionally creates this bean. The problem is that the fields in DataSourcePublicMetrics are all private making reuse difficult. The only solution i see is hide all the internal variables and override the public methods. Is there a better way? I'm using spring-boot 1.2.2.RELEASE.
Use composition instead of inheritance.
MyCustomMetrics implements PublicMetrics
Any bean the implements PublicMetrics is picked up by the actuator to be exposed at /metrics. DataSourcePublicMetrics implements this interface.
You then inject the DataSourcePublicMetrics bean into MyCustomMetrics (this could even be your custom DataSource, but probably better to create a different class). Implement the contract of PublicMetrics.
public Collection<Metric<?>> metrics()
Just defer it to the DataSourcePublicMetrics implementation, and also add whatever custom metrics you want.
I'm pretty new to the Spring Framework and I got problems to understand the #Required annotation in combination with a Java configured application.
Here is an example.
Config-File
#Configuration
public class AppConfig {
#Bean
public Movie movieA() {
return new Movie();
}
#Bean
public MovieHolder holder() {
return new MovieHolder();
}
}
MovieHolder.java
public class MovieHolder {
private Movie movie;
public Movie getMovie() {
return movie;
}
#Required
public void setMovie(Movie movie) {
this.movie = movie;
}
}
Context initialization
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
MovieHolder holder = (MovieHolder) context.getBean("holder");
System.out.println("movie: " + holder.getMovie());
As far as I understood the documentation of the #Required annotation, there should rise an exception, because movie isn't set directly or by autowiring. Instead is the output movie: null.
What am I doing wrong? Or isn't this the correct use of the #Required annotation?
Setting the required properties in the beans that you are instantiating is your own responsibility. The BeanPostProcessor that processes the bean-definitions in the classes annotated with #Configuration is called ConfigurationClassPostProcessor. The BeanPostProcessor that processes your #Required annotation defaults to RequiredAnnotationBeanPostProcessor, which is registered by default when you use context:annotation-config and context:component-scan in your configuration. If you are not using these two tags, you can even register your own RequiredAnnotationBeanPostProcessor as a bean.
Now, the default implementation of the RequiredAnnotationBeanPostProcessor has a method called boolean shouldSkip(..) that checks for a boolean attribute named SKIP_REQUIRED_CHECK_ATTRIBUTE. The value of this attribute is checked for each bean during the post-processing by the RequiredAnnotationBeanPostProcessor. If it returns false, the #Required constraint is enforced, otherwise it is not.
Now, the ConfigurationClassPostProcessor set the value of this attribute to true while creating the bean definitions from the #Configuration classes (I guess for the reason that if you are defining a bean, you should ensure that it has the required properties). Hence, the #Required is not enforced for such beans.
As an aside, You might think that where did this SKIP_REQUIRED_CHECK_ATTRIBUTE attribute come from and where is it set: it is set on the instances of BeanDefinition that are used by Spring internally for bean creation and post-processing.
If you really want to enforce the #Required constraints, you would have to override the RequiredAnnotationBeanPostProcessor, override the boolean shouldSkip(..) method and register this class instead of the default RequiredAnnotationBeanPostProcessor. And as the documentation for RequiredAnnotationBeanPostProcessor says:
A default RequiredAnnotationBeanPostProcessor will be registered by the "context:annotation-config" and "context:component-scan" XML tags. Remove or turn off the default annotation configuration there if you intend to specify a custom RequiredAnnotationBeanPostProcessor bean definition.
Another way would be to use the initMethod attribute on your #Bean annotation. Which could perform checks to see that the required properties are indeed set. However, since this is code based configuration, you could just as well call that init method yourself.
Also, in my opinion, there is not much point in going through a lot of trouble to use your own RequiredAnnotationBeanPostProcessor, as the following documentation says:
Please note that an 'init' method may still need to implemented (and may still be desirable), because all that this class does is enforce that a 'required' property has actually been configured with a value. It does not check anything else... In particular, it does not check that a configured value is not null.
So, to summarize: #Required doesn't work with #Configuration classes by default. If you need to make sure that all your properties are set, you can just as well do it yourself when you create the bean in the #Bean methods (By calling some init method that performs such validations, or just supplying the required properties yourself). And if you really need to make the #Required annotation work, you'd need to use your own implementation of the RequiredAnnotationBeanPostProcessor, register it as a bean in the spring context and give up the benefits of context:annotation-config.
Just tried to declare a #Bean RequiredAnnotationBeanPostProcessor with overridden shouldSkip() method.
Yes, it checks my beans, but it fails even if I set all the required properties, i.e. it always fails.
I think Spring has a real problem with supporting #Required annotation for Java Config, since Spring has no way to tell whether or not you have set the property when you do it directly in Java code. (It can't inspect for 'null' fields later, since this would mean changing the semantics of the #Required annotation which should allow explicitly set null values).
When you use an XML config, Spring creates a wrapper object to set the properties, so it can track all the configured 'setXxx()' operations.
Conclusion: there is no reasonable way to enable #Required annotation for beans created in Java #Configuration classes.
(Very unfortunate feature, in my opinion, since the bean class writer and the class user might be different persons).