Spring DI - Non-managed-object custom resolution - java

I have the following bean / constructor definitions:
#Configuration
class Configuration {
#Bean
public List<Something> getSomethings(MyFancyStuff stuff, #Autowired Bar bar) {
//...
}
}
#Component
class SomeOtherThing {
public SomeOtherThing(MyFancyStuff stuff, #Autowired Bar bar) {
//...
}
}
Is it possible to extends dependency resolution to provide a custom resolver when a specific class or annotation is found for a given parameter? I looked at PropertyPlaceholderConfigurer and InstantiationAwareBeanPostProcessor but nothing seemed to help me write my own value provider.
As a context: I implemented a custom scope which creates many instances of a given bean for each configuration object it has. I want to pass this configuration object to the bean-creation-process of said scope without adding it to the application context. I don't want to add it to the application context because it is an object which no other object should be able to obtain through dependency injection. I need to extend the DI-process of spring because I want to support field injection, constructor injection and bean factory-methods like the shown getSomethings
note: this is not about automatic value conversion of SpringMVC request parameters.

You can use #Conditional Annotation
#Bean(name="dataSource")
#Conditional(value=DevCondition.class)
public Util getSource1() {
return new DevUtil();
}
#Bean(name="dataSource")
#Conditional(ProdCondition.class)
public Util getSource2() {
return new ProdUtil();
}
you can also create bean based on property value using #Profile

Related

How to specify a default bean for autowiring in Spring?

I am coding both a library and service consuming this library. I want to have a UsernameProvider service, which takes care of extracting the username of the logged in user. I consume the service in the library itself:
class AuditService {
#Autowired
UsernameProvider usernameProvider;
void logChange() {
String username = usernameProvider.getUsername();
...
}
}
I want to have a default implementation of the UsernameProvider interface that extracts the username from the subject claim of a JWT. However, in the service that depends on the library I want to use Basic authentication, therefore I'd create a BasicAuthUsernameProvider that overrides getUsername().
I naturally get an error when there are multiple autowire candidates of the same type (DefaultUsernameProvider in the library, and BasicAuthUsernameProvider in the service), so I'd have to mark the bean in the service as #Primary. But I don't want to have the library clients specify a primary bean, but instead mark a default.
Adding #Order(value = Ordered.LOWEST_PRECEDENCE) on the DefaultUsernameProvider didn't work.
Adding #ConditionalOnMissingBean in a Configuration class in the library didn't work either.
EDIT: Turns out, adding #Component on the UsernameProvider implementation classes renders #ConditionalOnMissingBean useless, as Spring Boot tries to autowire every class annotated as a Component, therefore throwing the "Multiple beans of type found" exception.
You can annotate the method that instantiates your bean with #ConditionalOnMissingBean. This would mean that the method will be used to instantiate your bean only if no other UserProvider is declared as a bean.
In the example below you must not annotate the class DefaultUserProvider as Component, Service or any other bean annotation.
#Configuration
public class UserConfiguration {
#Bean
#ConditionalOnMissingBean
public UserProvider provideUser() {
return new DefaultUserProvider();
}
}
You've not posted the code for DefaultUsernameProvider but I guess its annotated as a #Component so it is a candidate for auto wiring, and the same with the BasicAuthUsernameProvider. If you want to control which of these is used, rather than marking them both as components, add a #Configuration class, and create your UsernameProvider bean there:
#Configuration
public class ProviderConfig {
#Bean
public UsernameProvider() {
return new BasicAuthUsernameProvider();
}
}
This bean will then be auto wired wherever its needed

Spring Boot auto configuration - Override an auto configured bean

I'm attempting to override a bean definition from a library auto configuration and it isn't working. I'm overriding the definition to return a bean of the interface type - my own implementation, whereas the library auto configuration bean returns a concrete implementation.
Spring is finding my bean at startup, then overriding it with the library bean. I've tried using #AutoConfigureAfter(LibraryConfig.class) and making my bean #Lazy but nothing seems to work.
I've spent many a year staying clear of 'magical' code and this type of thing is a good case in point.
Your question is indeed not clear, probably an example could help here.
Anyway, when an infrastructure-level bean is defined, the easiest way in spring boot to override it is just to provide your own configuration that will return the same interface (the bean with the given name)
for example, let's say, in some spring boot source/thirdparty there is the following code:
interface SomeInterface {...}
public class ThirdpartyInternalImplementation implementsSomeInterface {...}
#Configuration
public class ThirdPartyConfiguration {
#Bean
public SomeInterface someInterface () {
return new ThirdpartyInternalImplementation();
}
}
So now, let's assume, that in your source code you've provided another implementation of SomeInterface and you want to return it instead. So you should do something like this:
class MyCustomImplementation implements SomeInterface {}
..........................
#Configuration
public class MyOwnConfiguration {
#Bean
public SomeInterface someInterface() {
return MyCustomImplementation();
}
}
This should be enough to register your custom implementation of SomeInterface.

How to declare a Spring bean autowire-candidate="false" when using annotations?

I am using #ComponentScan and #Component to define my spring beans. What I would like is to declare one of these beans to be autowire-candidate=false.
This could be done with this attribute in xml. Isn't there the equivalent in annotations?
The reason I want this is because I have 2 implementations of the same interface and I don't want to use #Qualifier.
EDIT: Using #Primary is a valid work-around, but autowire-candidate seems to me like a useful feature with its own semantics.
Thanks
Looks like Spring refused autowire-candidate=false concept and it no longer supported. There is no analogue with annotations, so #Primary is the best work-around as you noticed.
Another way is to use custom org.springframework.beans.factory.support.AutowireCandidateResolver, which is used in DefaultListableBeanFactory, with logic that exclude undesirable beans from autowire candidates. In such case, the technology will be similar to that used for autowire-candidate=false in SimpleAutowireCandidateResolver.
Since Spring 5.1 , you can configure autowire-candidate in #Bean through autowireCandidate attribute:
#Bean(autowireCandidate = false)
public FooBean foo() {
return newFooBean();
}
You can also use the bean accessor to tune it's visibiltiy.
see Bean visibility
#Configuration
public abstract class VisibilityConfiguration {
#Bean
public Bean publicBean() {
Bean bean = new Bean();
bean.setDependency(hiddenBean());
return bean;
}
#Bean
protected Bean hiddenBean() {
return new Bean("protected bean");
}
}
You can then #Autowire the Bean class and it will autowire the public bean (without complaining about multiple matching beans)
As a class' definition (unless embedded) does not allow private / protected accessor the work around would be to use an #Configuration class that would instantiate all the beans an publish the public beans while hiding the private/protected (instead of directly annotating the classes #Component \ #Service)
Also package-protected accessor may worth a try to hide #Component annotated classes. I don't know if that may work.
We can do this by using the #Qualifier annotations with name mentioned in the #Component annotations
Bean classes -
#Component("fooFormatter")
public class FooFormatter implements Formatter {
public String format() {
return "foo";
}
}
#Component("barFormatter")
public class BarFormatter implements Formatter {
public String format() {
return "bar";
}
}
Injecting bean in service class -
public class FooService {
#Autowired
#Qualifier("fooFormatter")
private Formatter formatter;
}
For more details please refer - https://www.baeldung.com/spring-autowire#disambiguation. Above example taken from this link.

Enabling Spring method validation in JUnit test

I've followed the instructions in the Spring 4.0.5 documentation for configuring Bean Validation in the container, with Hibernate Validator 5.1 and this (Groovy) configuration class:
#Configuration("validationConfig")
#Import(CreatorConfig)
#ImportResource("/META-INF/spring/mockito-mocks.xml")
static class Config {
#Bean
validator() {
new LocalValidatorFactoryBean()
}
#Bean
mvpp() {
new MethodValidationPostProcessor()
}
}
My class being tested is instantiated in the referenced CreatorConfig class:
#Configuration
#DependsOn("validationConfig")
static class CreatorConfig {
#Bean
ticketCreator(TicketRepository tickets) {
new UploadTicketCreator(tickets)
}
}
I separated this out into a separate configuration class under the belief that I needed the postprocessor registered before creating the UploadTicketCreator bean, which is annotated according to the documentation:
#Validated
public class UploadTicketCreator {
public UploadTicket createTicket(#Valid CreateTicketRequest request) {
// do stuff
}
}
I'm then injecting the UploadTicketCreator into the test case. I've verified that the autowiring is operating properly (the field is populated, and its own tickets field is a Mockito mock). However, the validation logic is not being applied to my creator bean, and the injected bean is the raw POJO without any proxying.
Am I missing a piece of the validation setup? Is there an additional required step not mentioned in the documentation?
The Spring configuration processor appears to be inspecting the declared return type of the bean declarations. I was using Groovy's implicit return type, which presumably was compiled to Object, and adding an explicit return type of MethodValidationPostProcessor or even BeanPostProcessor caused the validation advice to be applied.

#Inject not injecting and causing NullPointerException using component scanning

My application context XML is simple:
<context:component-scan base-package="com.depressio.spring" />
In that package, I have my configuration:
package com.depressio.spring
#Configuration
#ComponentScan(basePackages = "com.depressio")
public class DepressioConfiguration
{
#Inject private ApplicationContext context;
}
Within com.depressio, there's a repository (DAO):
package com.depressio.dao;
#Repository
public class ParameterDAO
{
public Parameter getParameter(long ID) { ... }
}
... and a service where injection is working just fine (no NPE when parameterDAO is used):
package com.depressio.resource;
#Service
#Path("/depressio/parameters")
public class ParameterResource
{
#Inject private ParameterDAO parameterDAO;
#Path("{id}")
public Response getParameter(long parameterID)
{
return Response.ok(parameterDAO.getParameter(parameterID).legacyFormat()).build();
}
}
However, the legacyFormat() method call there constructs another object. Within that object, I have to inject a different DAO (also annotated with #Repository, though). That injection isn't working.
So, we have the original Parameter object:
package com.depressio.domain;
public class Parameter
{
...
public LegacyParameter legacyFormat()
{
return new LegacyParameter(this);
}
}
... and the LegacyParameter where the injection isn't working:
package com.depressio.domain.legacy;
public class LegacyParameter
{
#Inject private LegacyDAO legacyDAO;
....
public LegacyParameter(Parameter newParameter)
{
// NullPointerException when using the injected legacyDAO.
}
}
I've tried a few things, including:
Using an no-args constructor for LegacyParameter, then calling a populate method so I'm not using the injected DAO until after the object is constructed. This didn't work.
Injecting the LegacyDAO into the ParameterResource and passing it in. This worked, but isn't ideal since I have to pass it around a whole lot (which injection should help avoid, no?). It did prove that LegacyDAO is injectible... just not into LegacyParameter apparently.
Adding a #Service, #Component, or #Named annotation on LegacyParameter. All end up with the NullPointerException on the line I try to reference the injected legacyDAO.
What am I missing?
As Sotirios has pointed out, it can't work since you create a regular Java object and do not give Spring a chance to enhance it.
Either let Spring create objects for which you want to enjoy the Spring 'magic' (like setting #Inject dependencies etc).
Or create your own objects and set the dependencies yourself (yourObject.setDao(dao)).
That said, there are exceptional cases in which you still want to create your objects 'on the fly' by yourself but rely on Spring to inject dependencies to these objects. In this case you should call Spring explicitly:
LegacyParameter p = new LegacyParameter(...);
applicationContext.getAutowireCapableBeanFactory().autowireBean(p);
I don't think you really need it in your case.
(see this link inject bean reference into a Quartz job in Spring? for an example when this is really required).
In addition, I would advice to simplify your configuration.
Why do you use both xml-based and java-based configuration that do actually the same? In your example you could keep only one of them and have the same effect.

Categories

Resources