Spring Boot Quartz, Integration Inbound channel adapter and trigger bindings - spring-boot

We have Quartz Job + File Integration adapter using XML configurations and is working fine, however since trying to move to Spring Boot and these configurations to annotations
Below is the XML configuration for which I am looking for equivalent annotations and bindings
<bean id="scheduler"
class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="schedulerContextAsMap">
<map>
<entry key="inboundadapterendpoint"><ref bean="incomingfiles" /></entry>
<entry key="inboundendpointtrigger"><ref bean="incomingfiles-trigger"/></entry>
</map>
</property>
</bean>
<bean id="inboundendpointtrigger" class="abc.xyz.Trigger" />
<file:inbound-channel-adapter id="incomingfiles" channel="xyz" directory="" scanner="recursiveScanner" auto-startup="false" prevent-duplicates="false">
<integration:poller task-executor="fileChannelTaskExecutor" trigger="incomingfiles-trigger" max-messages-per-poll="1">
</integration:poller>
</file:inbound-channel-adapter>
How do we get the Inbound Adapter Bean & poller trigger
created using annotations below is injected during scheduler factory creation in spring Boot quartz config
#Bean
#InboundChannelAdapter(poller = #Poller(trigger="customTrigger")
public MessageSource<File> fileReadingMessageSource() {
}
Thanks in advance for any help or suggestions regarding the same
Artem Bilan, thanks very much for the response.
Follow up question post trying out the code provided in response
#Configuration
public class QuartzConfig {
#Autowired
private CustomTrigger inboundEndPointTrigger;
#Autowired
private AbstractEndpoint incomingFiles;
#Bean
public SchedulerFactoryBean schedulerFactoryBean() {
System.out.println("incomingFiles value is " + incomingFiles);
}
}
#Bean(name = "incomingFiles")
#InboundChannelAdapter(autoStartup = "false", value = "xyz", poller = #Poller(trigger = "inboundEndPointTrigger", maxMessagesPerPoll = "2", errorChannel = "abc"))
public MessageSource<File> fileReadingMessageSource() {
}
Output of above is reference for errorLogger instead of Inbound Channel Adapter.
incomingFiles value is bean '_org.springframework.integration.errorLogger'
How do i bind the exact Inbound Adapter with name incomingFiles to scheduler factory ?
Update after trying out with #EndPointId...
#Bean
#EndPointId("incomingFiles")
#InboundChannelAdapter(autoStartup = "false", value = "xyz", poller = #Poller(trigger = "inboundEndPointTrigger", maxMessagesPerPoll = "2", errorChannel = "abc"))
public MessageSource<File> fileReadingMessageSource() {
}
System.out.println("incomingFiles value is " + incomingFiles); print in QuartzConfig class above is still giving a reference to Logger object
incomingFiles value is bean '_org.springframework.integration.errorLogger'
Found the response in below SO (Spring Cloud Stream + Quartz ) on how the bean will be created for Inbound Channel Adapter.
Since the AbstractEndPoint is returning the logger reference instead of InboundChannelAdapter ,
is it ok to get the Inbound Adapter channel bean reference via application context in scheduler factory ? are there any issues with this ?
try {
ApplicationContext applicationContext = (ApplicationContext) context.getScheduler().getContext().get("applicationContext");
AbstractEndpoint abstractEndPoint = (AbstractEndpoint) applicationContext
.getBean("fileConfig.fileReadingMessageSource.inboundChannelAdapter");
} catch(SchedulerException ex) {
}
fileConfig is the Spring File integration configuration class name where InboundChannelAdapter is defined..

I'm not sure why you have closed your old question - you could just edit it properly and we would have a link to other question. But anyway, the answer is like this:
Any XML bean definition could be declared in Java & annotation config with a #Bean method definition.
So, that <bean id="inboundendpointtrigger" class="abc.xyz.Trigger" /> would be in Java like this:
#Bean
Trigger customTrigger() {
return new abc.xyz.Trigger();
}
You already use its bean name as a reference in the #Poller.
The same you do for the SchedulerFactoryBean and configure its setSchedulerContextAsMap() in that #Bean method. You have already a customTrigger() bean for reference and do get access to the SourcePollingChannelAdapter endpoint based on the #InboundChannelAdapter, you need to inject into a #Bean method. Kinda this:
#Bean
SchedulerFactoryBean schedulerFactory(Trigger trigger, SourcePollingChannelAdapter endpoint) {
}
Don't forget to use an #InboundChannelAdapter(autoStartup = "false") as Gary recommends in other SO question.

Related

Using spring to load properties as System properties

I'm using Spring 4.1.6.
I have something like the following:
foo.properties:
valueX=a
valueY=b
Spring bean:
<context:property-placeholder location="classpath:foo.properties" ignore-unresolvable="false" ignore-resource-not-found="false" />
<bean id="foo" class="com.foo.bar.MyClass" >
<property name="someValue" value="${valueX}" />
</bean>
I have a non-Spring class which also needs to use a value from foo.properties.
Non Spring Class:
public void doSomething() {
String valueY = System.getProperty("valueY");
}
When Spring loads foo.properties, is there a way to populate all the properties into System properties so that I can get "valueY" using System.getProperty("valueY").
I don't want to load foo.properties again in my non-Spring class.
The context:property-placeholder will create a PropertySourcesPlaceholderConfigurer config bean for you. You cannot access the properties from this bean programatically as stated here.
What you can do is to load the properties into a separate spring bean as given below.
#Bean(name = "mapper")
public PropertiesFactoryBean mapper() {
PropertiesFactoryBean bean = new PropertiesFactoryBean();
bean.setLocation(new ClassPathResource("application.properties"));
return bean;
}
and then set the system property when the context load is finished using a listener as given below. Got the code from this answer
#Component
public class YourJobClass implements ApplicationListener<ContextRefreshedEvent> {
#Resource(name = "mapper")
private Properties myTranslator;
public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
System.setProperties(myTranslator);
}
}

Spring and jackson, how to disable FAIL_ON_EMPTY_BEANS through #ResponseBody

Is there a global configuration in spring that can disable spring FAIL_ON_EMPTY_BEANS for all controller annotated with #ResponseBody?
If you are using Spring Boot, you can set the following property in application.properties file.
spring.jackson.serialization.FAIL_ON_EMPTY_BEANS=false
Thanks to #DKroot for his valuable comment. But I believe this should be its own answer for others.
You can configure your object mapper when configuring configureMessageConverters
#Bean
public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() {
ObjectMapper mapper = new ObjectMapper();
mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
MappingJackson2HttpMessageConverter converter =
new MappingJackson2HttpMessageConverter(mapper);
return converter;
}
If you want to know how to do exactly in your application, please update your question with your configuration files (xml or java configs).
Here is a good article how to customize message converters.
Edit: If you are using XML instead of Java configs, you can create a custom MyJsonMapper class extending ObjectMapper with custom configuration, and then use it as follows
public class MyJsonMapper extends ObjectMapper {
public MyJsonMapper() {
this.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
}
}
In your XML:
<mvc:annotation-driven>
<mvc:message-converters>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="objectMapper" ref="jacksonObjectMapper" />
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
<bean id="jacksonObjectMapper" class="com.mycompany.example.MyJsonMapper" >
cant find spring.jackson.serialization.FAIL_ON_EMPTY_BEANS=false in spring boot 2.2.5
I use this
#Configuration
public class SerializationConfiguration {
#Bean
public ObjectMapper objectMapper() {
return new ObjectMapper().disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
}
}
If you are using Spring Boot / JPA , you also have to observe if you are using
getOne (goes for jpa getReference ) for the findOne / enetiyManager.find(Clazz , id)
GetOne Relies on Persistence cached reference by ID that is designed to retrieve entity with only ID in it. Its use was mostly for indicating reference existed without the need to retrieve whole entity.
The find method is straight forward to persistence manager to obtain the persistent instance.
This second one will observe you annotation #JsonIgnore accordingly and will give you the expected result.
// On entity...
#JsonIgnore
#OneToMany(fetch = FetchType.LAZY, mappedBy = "foo")
private List<Foo> fooCollection;
// later on persistence impl
entityManager.find(Caso.class, id);
// or on serivce
casoRepository.findById(id); //...
For me, the Issue was with typecasting from org.json.JSONObject object to org.json.simple.JSONObject and I solved it by parsing value from org.json.JSONObject and then cast it to use as org.json.simple.JSONObject
JSONParser parser = new JSONParser();
org.json.simple.JSONObject xmlNodeObj = (org.json.simple.JSONObject) parser.parse(XMLRESPONSE.getJSONObject("xmlNode").toString());

Ldap Query - Configuration using Spring Boot

I have a Spring boot application that needs to perform LDAP queries. I'm trying to take the following recommendation from the Spring boot documentation:
"Many Spring configuration examples have been published on the
Internet that use XML configuration. Always try to use the equivalent
Java-base configuration if possible."
In a Spring XML configuration file, I would have used:
<ldap:context-source
url="ldap://localhost:389"
base="cn=Users,dc=test,dc=local"
username="cn=testUser"
password="testPass" />
<ldap:ldap-template id="ldapTemplate" />
<bean id="personRepo" class="com.llpf.ldap.PersonRepoImpl">
<property name="ldapTemplate" ref="ldapTemplate" />
</bean>
How would I configure this using a Java-based configuration? I need to be able to change URL, base, username, and password attributes of ldap:context-source without a code rebuild.
The <ldap:context-source> XML tag produces an LdapContextSource bean and the <ldap:ldap-template> XML tag produces an LdapTemplate bean so that's what you need to do in your Java configuration:
#Configuration
#EnableAutoConfiguration
#EnableConfigurationProperties
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#Bean
#ConfigurationProperties(prefix="ldap.contextSource")
public LdapContextSource contextSource() {
LdapContextSource contextSource = new LdapContextSource();
return contextSource;
}
#Bean
public LdapTemplate ldapTemplate(ContextSource contextSource) {
return new LdapTemplate(contextSource);
}
#Bean
public PersonRepoImpl personRepo(LdapTemplate ldapTemplate) {
PersonRepoImpl personRepo = new PersonRepoImpl();
personRepo.setLdapTemplate(ldapTemplate);
return personRepo;
}
}
To allow you to change the configuration without a rebuild of your code, I've used Spring Boot's #ConfigurationProperties. This will look in your application's environment for properties prefixed with ldap.contextSource and then apply them to the LdapContextSource bean by calling the matching setter methods. To apply the configuration in the question, you can use an application.properties file with four properties:
ldap.contextSource.url=ldap://localhost:389
ldap.contextSource.base=cn=Users,dc=test,dc=local
ldap.contextSource.userDn=cn=testUser
ldap.contextSource.password=testPass

How to create programmatically a spring PublishSubscribeChannel

I want to create programmatically the following XML config
<int:channel id="sample">
</int:channel>
What i can do is the following
PublishSubscribeChannel channel = new PublishSubscribeChannel();
But there is no method to assign the id.
Actually <int:channel> produces DirectChannel bean.
And if you want to do it programatically and have entire Messaging Infrastructure you should configure it as bean anyway:
#Configuration
public class MyConfiguration {
#Bean
public MessageChannel sample() {
return new DirectChannel();
}
}
The id attribute is a key feature of Spring IOC container and, of course, it isn't responcibility of concrete class.
Seems to me you should to take a look into the new stuff of Spring Integration 4.0.
The "id" is specific to a Spring application context and helps identify each instance that is being defined inside the application context.
What you have in there translates, more "verbosely" to this Spring config:
<bean id="sample" class="org.springframework.integration.channel.DirectChannel" />
The "id" identifies, like a name, a class DirectChannel instance within the context of a Spring ApplicationContext. The default channel used for a "int:channel" definition is the DirectChannel class, not PublishSubscribeChannel (DirectChannel).
But, apart from the channel itself, Spring Integration creates some other beans behind the scene.
Another way of wiring/injecting DirectChannel Bean: For Spring 3.2.3.RELEASE version
Code in Controller/Config Loader file:
#Configuration
public class ConfigControllerLoader {
#Autowired
#Qualifier("direct-channel-bean")
DirectChannel drtChannel;
}
Context file bean definition:
<int:channel id="direct-channel-bean"></int:channel>

Limit accessible scope (#Autowire/#Resource) of a Spring Bean to a package

How do you limit the accessible scope of a spring bean?
Is this even possible, or recommended?
I ask, as I have a case where I would like a ConnectionManager class to #Autowired #Resource each of its specific IExternalConnections (in case I later need separate ConnectionManager classes).
However, I don't want other classes using those connections directly. It would make sense to me to have some way of making the IExternalConnection beans package private.
Most questions about Spring Bean scope relate to the lifetime of the Bean, which is specifically not what this question is about
Edit:
Here's some code snippets to clarify what I mean
public class ConnectionFactory {
#Resource(name = "defaultConnectionManager")
private IExternalConnectionManager defaultConnectionManager;
#Resource(name = "someOtherConnectionManager")
private IExternalConnectionManager someOtherConnectionManager;
}
The configuration class:
#Configuration
public class Connections {
#Bean
public ConnectionFactory defaultConnectionFactory() {
return new ConnectionFactory();
}
#Bean
public IExternalConnectionManager defaultConnectionManager() {
return new defaultConnectionManager();
}
#Bean
public IExternalConnectionManager someOtherConnectionManager() {
return new someOtherConnectionManager();
}
}
The goal being making Connections only provide the defaultConnectionFactory Bean, and not defaultConnectionManager or someOtherConnectionManager
Would something like this work for you ?
Define the second bean with in the scope of first bean
<bean class="connectionFactory" >
<property name="defaultConnectionManager">
<bean class="com.xyz.Connectionmanager" >
<property name="connection">
<bean class="com.xyz.Connection" ></bean>
</property>
</bean>
</property>
</bean>

Resources