i want to know why #Value property injection works on classes with #Service annotation but not on classes with #Bean within #Configuration annotated class.
Works means that the property value is not null.
This value is also injected into two other service which i see during debugging in DefaultListableBeanFactory.doResolveDependency. But i dont see the bean WebserviceEndpoint.
Configuration
#Configuration
public class WebserviceConfig {
// do some configuration stuff
#Bean
public IWebserviceEndpoint webserviceEndpoint() {
return new WebserviceEndpoint();
}
}
Webservice interface
#WebService(targetNamespace = "http://de.example/", name = "IWebservice")
#SOAPBinding(parameterStyle = SOAPBinding.ParameterStyle.BARE)
public interface IWebserviceEndpoint {
#WebMethod
#WebResult(name = "response", targetNamespace = "http://de.example/", partName = "parameters")
public Response callWebservice(#WebParam(partName = "parameters", name = "request", targetNamespace = "http://de.example/") Request request) throws RequestFault;
}
Webservice class
public class WebserviceEndpoint implements IWebserviceEndpoint {
#Value("${value.from.property}")
private String propertyValue;
}
application.yml
value:
from:
property: property-value
When does the injection of #Value happen in this case.
Basically propertyValue is null because Spring injects value after bean's creation.
So when you do:
#Bean
public IWebserviceEndpoint webserviceEndpoint() {
return new WebserviceEndpoint();
}
Spring creates a new instance with propertyValue=null.
You can initialize your instance attribue with #ConfigurationProperties
#Bean
#ConfigurationProperties(prefix=...)
public IWebserviceEndpoint webserviceEndpoint() {
return new WebserviceEndpoint();
}
Note that propertyValue should have a setter.
You have several ways to solve this problem, usually it's good to centralize properties in one utils class.
#Component
public class Configs {
#Value("${propery}"
String property;
String getProperty(){
return property;
}
}
And then:
#Bean
#ConfigurationProperties(prefix=...)
public IWebserviceEndpoint webserviceEndpoint() {
WebserviceEndpoint we = new WebserviceEndpoint();
we.setProperty(configs.getProperty())
return we;
}
Again there are many many different ways to solve this problem
Related
Using Springboot2 and java8.
I've a #Configuration class, that will instantiate a bean depending on some properties, and depending on those properties, the bean instantiated should be Primary or not.
#Configuration
public class MyConfClass {
#Autowired
private MyProperties myProperties;
#Bean
#ConditionalOnProperty(name = "property.use-default", havingValue = "false", matchIfMissing = true)
public MySpringBean buildMySpringBean() {
MySpringBean bean = new MySpringBean();
if (myProperties.isPrimary()) {
// Should be primary like if annotated with #Primary
} else {
// should not
}
return bean;
}
}
In general You might try to create your own BeanFactoryPostProcessor that will
set Primary parameter to bean definition based on configuration, however it means that you'll dive pretty deep into spring internals.
If you don't want to fiddle with this pretty advanced concept,
Probably you can go with following approach:
#Configuration
public class MyConfClass {
#Bean
#Primary
#ConditionalOnProperty(name = "shouldBeDefault", havingValue = "true", matchIfMissing = true)
public MySpringBean buildMySpringBeanPrimary() {
return new MySpringBean();
}
#Bean
#ConditionalOnProperty(name = "shouldBeDefault", havingValue = "false", matchIfMissing = false)
public MySpringBean buildMySpringBeanNotPrimary() {
return new MySpringBean();
}
Frankly I didn't understand what is property.use-default property, but if you also have to be dependent on this condition, then probably you'll have to prepare "compound conditional" that will evaluate to "true" only if both "underlying" conditions are true.
This can be done easily as explained Here
Update
Since it looks like you're going to use BeanFactoryPostProcessor here, this is the example that should work (probably with minor changes):
#Component // or register it in #Configuration as if its a regular bean
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
private final Environment env;
public MyBeanFactoryPostProcessor(Envrionment env) {this.env = env;}
public void postProcessBeanFactory(ConfiguratbleListableBeanFactory beanFactory) throws BeansException {
boolean shouldBePrimary = resolveShouldBePrimary();
if(shouldBePrimary) {
BeanDefinition bd = beanFactory.getBeanDefinition("yourBeanName");
bd.setPrimary(true);
}
}
private boolean resolveShouldBePrimary() {
// here you can read properies directly or if you work with #ConfigurationProperties annotated class you can do:
MyConfigProperties myConfigProperties = Binder.get(env).bind("prefix.in.config", MyConfigProperties.class).get()
// now resolve from the mapped class
}
}
I am struggling with a way to autowire a dependency within a converter class using spring boot. What is the most elegant solution to solve this problem?
Configuration
#Configuration
public class Config {
#Bean
public ConversionServiceFactoryBean conversionFacilitator() {
ConversionServiceFactoryBean factory = new ConversionServiceFactoryBean();
factory.setConverters(getConverters());
return factory;
}
private Set<Converter> getConverters() {
Set<Converter> converters = new HashSet<>();
converters.add(new MyConverter());
return converters;
}
}
Converter class
#Component
public class MyConverter implements Converter<Type1, Type2> {
#Autowired
private Dependency dependency; // Null here due to the component not being injected
#Override
public Type2 convert(Type1 type1) {
return dependency.something(type1);
}
}
The dependency is not being injected because you are creating MyConverter with new, instead of let Spring create it.
You do not need a method to return set of converters. Spring can do it for you, just auto wiring it. Spring is smart enough to give you a set with all the converter implementations it finds.
You should use something like:
#Configuration
public class Config {
#Bean
#Autowired
public ConversionServiceFactoryBean conversionFacilitator(Set<Converter> converters) {
ConversionServiceFactoryBean factory = new ConversionServiceFactoryBean();
factory.setConverters(converters);
return factory;
}
}
I am trying to inject a value into a Custom Annotation but Spring doesn't seem to be evaluating.
Here is my annotation:
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
public #interface MyCustomAnno {
String var1();
String var2();
}
Here is my Bean (it is created in a Spring Configuration file) with Annotation:
public class MyClass {
#MyCustomAnno(var1 = "${some.property.one}",
var2 = "${some.property.two}")
public void someMethod() {
// do something here
}
}
Here is the Aspect where I am trying to use the values passed into the annotation:
#Aspect
public class MyAop {
#Around(value="#annotation(myCustomAnno)",argNames="myCustomAnno")
public Object aroundMethod(MyCustomAnno myCustomAnno) {
int intVar1 = Integer.parseInt(myCustomAnno.var1());
int intVar2 = Integer.parseInt(myCustomAnno.var2());
// ....
}
}
In the around method I am receiving a NumberFormatException: For input string: ${some.property.one}. This means that Spring didn't inject the value for some reason.
In case you are wondering, in the same class I can do the normal #Value annotation and the value gets injected properly:
#Value("${some.property.one}")
private propertyOne; // This works
Is it possible to do what I want to and if so, how?
AFAIK, placeholders are not resolved in custom annotations. However you could resolve them in the Aspect itself.
For example:
#Aspect
class MyAop implements EmbeddedValueResolverAware {
private StringValueResolver resolver;
#Around(value="#annotation(myCustomAnno)",argNames="myCustomAnno")
public void play(MyCustomAnno ann) {
System.out.println(resolver.resolveStringValue(ann.var1()));
}
#Override
public void setEmbeddedValueResolver(StringValueResolver resolver) {
this.resolver = resolver;
}
}
I have RepositoryConfig extending Neo4jConfiguration. The latter sets up a number of beans with #Bean annotated methods. RepositoryConfigoverrides getGraphDatabaseService which is invoked before any fields in RepositoryConfig are autowired. That is a problem since I want to use the autowired stuff inside the getGraphDatabaseServicemethod.
#ConfigurationProperties(prefix = "neo4j")
public class RepositoryProperties {
[...]
}
#Configuration
#EnableNeo4jRepositories("com.foo.bar")
#EnableConfigurationProperties(RepositoryProperties.class)
public class RepositoryConfig extends Neo4jConfiguration {
#Autowired
private RepositoryProperties properties;
#Override
#Bean(name = "graphDatabaseService", destroyMethod = "shutdown")
public GraphDatabaseService getGraphDatabaseService() {
[...] // properties is 'null' at this point
}
#PostContstruct
public void foo() {
[...] // properties is initiated OK here
}
}
Why is getGraphDatabaseServicebeing called before autowiring is complete? I guess it has to do with the inheritance... If I remove the inheritance then autowiring is complete at the time getGraphDatabaseServiceis called. I've also tried annotating the method with #DependsOn, with no luck.
Any ideas is much appreciated!
Yes, I have seen this too occasionally. I think there are two workarounds.
Option 1. Autowire the bean definition
#Override
#Bean(name = "graphDatabaseService", destroyMethod = "shutdown")
#Autowired
public GraphDatabaseService getGraphDatabaseService() {
[...] // properties is 'null' at this point
}
Option 2. Inject the bean
#Override
#Bean(name = "graphDatabaseService", destroyMethod = "shutdown")
public GraphDatabaseService getGraphDatabaseService(#Autowired RepositoryProperties properties) {
// can probably delete the Config member with this approach
[...] // properties is 'null' at this point
}
It seems that the setter on my bean is not working.
This is my Spring java configuration, SpringConfig.java:
#Configuration
#ComponentScan("com.xxxx.xxxxx")
public class SpringConfig {
#Bean(name="VCWebserviceClient")
public VCWebserviceClient VCWebserviceClient() {
VCWebserviceClient vCWebserviceClient = new VCWebserviceClient();
vCWebserviceClient.setSoapServerUrl("http://localhost:8080/webservice/soap/schedule");
return vCWebserviceClient;
}
The VCWebserviceClient.java:
#Component
public class VCWebserviceClient implements VCRemoteInterface {
private String soapServerUrl;
public String getSoapServerUrl() {
return soapServerUrl;
}
public void setSoapServerUrl(String soapServerUrl) {
this.soapServerUrl = soapServerUrl;
}
// Implemented methods...
}
My app.java:
ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
VCWebserviceClient obj = (VCWebserviceClient) context.getBean("VCWebserviceClient");
System.out.println("String: "+obj.getSoapServerUrl()); // returns NULL
Why is obj.getSoapServerUrl() returning NULL?
This example shows how it should work.
The instance returned by VCWebserviceClient is not the one actually used by your application. It is a way for Spring to know what class to instanciate.
Any way, for you issue, use the #Value (http://docs.spring.io/spring/docs/3.0.x/reference/expressions.html)
#Component
public class VCWebserviceClient implements VCRemoteInterface {
// spring resolves the property and inject the result
#Value("'http://localhost:8080/webservice/soap/schedule'")
private String soapServerUrl;
// spring automatically finds the implementation and injects it
#Autowired
private MyBusinessBean myBean;
public String getSoapServerUrl() {
return soapServerUrl;
}
public void setSoapServerUrl(String soapServerUrl) {
this.soapServerUrl = soapServerUrl;
}
// Implemented methods...
}