SpringBoot multiple #Configuration and SOAP clients - spring-boot

I have tried to follow this simple tutorial https://spring.io/guides/gs/consuming-web-service/, and it works.
I then try to connect to another SOAP service, with an additional #Configuration and client-class extending WebServiceGatewaySupport. It seems that both client-classes then use the same #Configuration-class, making the one I added first failing (unknown jaxb-context etc.). How can I ensure that the client-classes use the correct #Configuration-class?

TL;DR: You have to match the name of the "marshaller()" method with the param variable name in your client configuration.
Overriding bean definitions
What is happening is that both of your #Configuration clases are using the same bean name for the Jaxb2Marshaller, that is (using the spring example):
#Bean
public Jaxb2Marshaller marshaller() { //<-- that name
Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
marshaller.setContextPath("hello.wsdl");
return marshaller;
}
There the "marshaller()" method name is the bean name that will be injected below in your client:
#Bean
public QuoteClient quoteClient(Jaxb2Marshaller marshaller) { //<-- used here
QuoteClient client = new QuoteClient();
client.setDefaultUri("http://www.webservicex.com/stockquote.asmx");
client.setMarshaller(marshaller);
client.setUnmarshaller(marshaller);
return client;
}
If you use "marshaller()" for your second client, Spring overrides that bean definition. You could spot this in the log file, look for something like this:
INFO 7 --- [main] o.s.b.f.s.DefaultListableBeanFactory : Overriding bean definition for bean 'marshaller'
Solution
So to create more clients that have their own marshaller without colliding you need to have a #Configuration like this:
#Configuration
public class ClientBConfiguration {
#Bean
public Jaxb2Marshaller marshallerClientB() {
Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
marshaller.setContextPath("hello.wsdl");
return marshaller;
}
#Bean
public ClientB clientB(Jaxb2Marshaller marshallerClientB) {
ClientB client = new ClientB();
client.setDefaultUri("http://www.webservicex.com/stockquote.asmx");
client.setMarshaller(marshallerClientB);
client.setUnmarshaller(marshallerClientB);
return client;
}
}
More about bean overriding: https://blog.tratif.com/2018/03/08/when-two-beans-collide/
Answer about spring boot #Configuration classes: Why Spring Boot Application class needs to have #Configuration annotation?

I ended up creating #Bean in the #Configuration-classes that returns a WebServiceTemplate. That is, I don't use Spring's autoconfiguration mechanisms. I removed the extend WebserviceGatewaySupport, and use #Autowired to autowire the WebserviceTemplateBean bean created in the #Configuration class.

Related

Does spring inject any beans provided in the #Configuration class

If I have a #Configuration class where I have a bean like below, will the dataMap be resolved in the constructor of the DataService class. What type of dependency injection is this? Is it by type because the name for sure doesn't match?
#Bean
public Map<String, List<Data>> data() {
final Map<String, List<Data>> dataMap = new HashMap<>();
readings.put("1", new Data());
return dataMap;
}
and a class
#Service
public class DataService {
private final Map<String, List<Data>> information;
public DataService(Map<String, List<Data>> information) {
this.information = information;
}
}
#Configuration annotation serves as a placeholder to mention that whichever classes annotated with #Configuration are holding the bean definitions!
When Spring application comes up, spring framework will read these definitions and create beans (or simply objects) in IOC (Inversion of control) container These would be Spring managed objects/beans !
To answer your question, it should create a bean and this is a setter based injection!
However, your #Bean must be some user defined or business entity class in ideal scenarios!
Few links for you to refer to:
https://www.codingame.com/playgrounds/2096/playing-around-with-spring-bean-configuration
https://www.linkedin.com/pulse/different-types-dependency-injection-spring-kashif-masood/

Ignore JNDI-Resource injection (#Resource) in Spring

I am currently experimenting with Spring Boot and I'm trying to include a library class which is currently used in a Java EE context.
Said class has a parent class which has a #Resource injection with a JNDI lookup name.
In a reduced example, the involved classes look like this:
Configuration.java
#Configuration
public class Facades {
#Bean
public Connection connection() {
return new Connection();
}
#Bean
public Facade facade(Connection connection) {
return new Facade(connection);
}
}
Facade + ParentFacade
public class ParentFacade {
#Resource(lookup = "eis/Connection") // <-- the problem
protected Connection connection;
}
public class Facade extends ParentFacade {
public Facade(Connection connection) {
this.connection = connection;
}
}
When I run the application, following error appears:
Invalid bean definition with name 'eis/Connection' defined in JNDI
environment: JNDI lookup failed; nested exception is
javax.naming.NoInitialContextException: Need to specify class name in
environment or system property, or as an applet parameter, or in an
application resource file: java.naming.factory.initial
Obviously, I don't need the #Resource injection since I can inject the connection by constructor.
However, Spring always attempts to inject a bean with the JNDI name dynamically.
I have tried to exclude the class from IoC inclusion with following annotations, but it made no difference:
#Configuration
#ComponentScan(
basePackages = "the.package",
excludeFilters = #ComponentScan.Filter(
type = FilterType.ASSIGNABLE_TYPE,
classes = { Facade.class, ParentFacade.class }
)
)
My question now is:
Can I either
make Spring ignore the #Resource annotation in the problematic class OR
inject a #Bean with the required JNDI-name (eis/Connection)?
Thanks in advance!
P.S.:
changing the library class which contains the #Resource annotation is not an option
I think, you need #Resource(name = "connection")

Could not autowire. No beans of 'InstructionRepository' type found

Trying to create a bean in SpringBoot application, but getting the following error "Could not autowire. No beans of 'InstructionRepository' type found."
InstructionRepository is annotated with #Repository annotation in the jar and is an Interface extending a Spring Data Interface
ScheduleProcessor is a method
When I Try adding the #ComponentScan annotation by passing the base package value, the error goes away BUT, when I boot up the application get the following error
Parameter 0 of constructor in com.xxx.resync.config.AppConfig required a bean of type 'com.xxx.repo.InstructionRepository' that could not be found. Action: Consider defining a bean of type 'com.xxx.repo.InstructionRepository' in your configuration.
#Configuration
#EnableAutoConfiguration
//#ComponentScan(basePackages = {"com.xxx.repo"})
public class AppConfig {
#Value("${pssHttp.connectTimeout:3000}")
private int connectTimeout;
#Bean
public RestTemplate getRestTemplate() {
RestTemplate restTemplate = new RestTemplate();
final HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory();
factory.setConnectTimeout(connectTimeout);
factory.setReadTimeout(connectTimeout);
restTemplate.setRequestFactory(factory);
return restTemplate;
}
#Bean
public ScheduleUpdater getScheduleUpdater() {
return new ScheduleUpdater(true);
}
#Bean
public ScheduleProcessor scheduleProcessor(InstructionRepository instructionRepository, ScheduleUpdater scheduleUpdater) {
return new ScheduleProcessor(instructionRepository, scheduleUpdater);
}
}
InstructionRepository
#Repository
public interface InstructionRepository extends CouchbaseRepository<Instruction, String> {
}
How can we fix the error and be able to boot up the Spring boot application?
Any suggestions appreciated.
You need to add #EnableCouchbaseRepositories to enable repo building eg to AppConfig.

Togglz with Spring #Configuration bean

I'm trying to implement Togglz & Spring using #Configuration beans rather than XML. I'm not sure how to configure the return type of the Configuration bean. For example:
#Configuration
public class SystemClockConfig {
#Bean
public SystemClock plainSystemClock() {
return new PlainSystemClock();
}
#Bean
public SystemClock awesomeSystemClock() {
return new AwesomeSystemClock();
}
#Bean
public FeatureProxyFactoryBean systemClock() {
FeatureProxyFactoryBean proxyFactoryBean = new FeatureProxyFactoryBean();
proxyFactoryBean.setActive(awesomeSystemClock());
proxyFactoryBean.setInactive(plainSystemClock());
proxyFactoryBean.setFeature(Features.AWESOME_SYSTEM_CLOCK.name());
proxyFactoryBean.setProxyType(SystemClock.class);
return proxyFactoryBean;
}
}
The systemClock method returns a FeatureProxyFactoryBean but the clients of this bean require a SystemClock. Of course, the compiler freaks over this.
I imagine it just works when XML config is used. How should I approach it when using a configuration bean?
I'm not an expert for the Java Config configuration style of Spring, but I guess your systemClock() method should return a proxy created with the FeatureProxyFactoryBean. Something like this:
#Bean
public SystemClock systemClock() {
FeatureProxyFactoryBean proxyFactoryBean = new FeatureProxyFactoryBean();
proxyFactoryBean.setActive(awesomeSystemClock());
proxyFactoryBean.setInactive(plainSystemClock());
proxyFactoryBean.setFeature(Features.AWESOME_SYSTEM_CLOCK.name());
proxyFactoryBean.setProxyType(SystemClock.class);
return (SystemClock) proxyFactoryBean.getObject();
}
But I'm not sure if this is the common way to use FactoryBeans with Spring Java Config.

Spring #Configuration class needs to be autowired

I've created a Spring #Configuration annotated class and I want to autowire a ResourceLoader to it so that I can use it in one of the #Bean methods to lookup a file given by a String. When I am running the app and initialising the context I get a NPE accessing the autowired field, and in debug mode it is shown as being null/not set. Am I wrong expecting the resourceLoader to be present? Am I wrong asserting the autowiring of the Configuration bean happens before its methods get called? The xml configuration loading this bean is tagged with <context:annotation-config/>
#Configuration
public class ClientConfig {
#Autowired
private ResourceLoader resourceLoader;
public #Bean
String configHome() {
return System.getProperty("CONFIG_HOME");
}
public #Bean
PropertiesFactoryBean appProperties() {
String location = "file:" + configHome() + "/conf/webservice.properties";
PropertiesFactoryBean factoryBean = new PropertiesFactoryBean();
factoryBean.setLocation(resourceLoader.getResource(location));
return factoryBean;
}
}
I'm not sure whether this is a bug or is the expected behavior. Sometimes it worked for me, sometimes didn't. Anyway, there is another way of achieving what you want:
public #Bean PropertiesFactoryBean appProperties(ResourceLoader resourceLoader) {
// resourceLoader is injected correctly
...
}

Resources