How to use MyBatis and Camel and Spring with annotations (interface Mapper) - spring

How to use MyBatis with Camel flow with Spring(Boot) WITH annotations (intefrace)?
It is working fine when I use Mybatis configuration in XML file.
Like:
<to uri="mybatis:selectSomething...">
(old fashion of springboot|camel)
with:
<mapper namespace="Something">
<resultMap id="SomeObject" type="SomeObjectImpl">
...
</resultMap>
<select id="selectSomething" resultMap="SomeObject">
SELECT something FROM somewhere WHERE id = #{id}
</select>
...
Now I have:
public interface Mapper {
#Select("SELECT something FROM somewhere WHERE id = #{id}")
public List<String> selectSomething(#Param("id") int id);
}
and it is working fine when I use it directly form java code.
But NOT working with camel flow
<to uri="mybatis:???...
There is no ID of select/statement which I can use.

This is not supported in camel-mybatis at this time of writing. But its a good idea to let us look into adding support for that. You are welcome to log a JIRA ticket at Apache Camel.

Related

Spring Batch Late Binding Within SQL Using Java Config

We are converting xml-based spring batch configuration to java config.
In xml form of JdbcCursorItemReader we were using late binding:
SELECT * FROM MY_TABLE_#{jobParameters[param1]}
How can this be implemented using Java config syntax?
You can achieve this as follows:
#Bean
#StepScope
public JdbcCursorItemReader jdbcCursorItemReader(#Value("#{jobParameters['param1']}") String param1) {
return new JdbcCursorItemReaderBuilder<>()
.sql("SELECT * FROM MY_TABLE_" + param1)
// set other properties
.build();
}
The reference documentation contains a toggle on each page that allows you to see examples in either Java and Xml configuration. This can be helpful in your migration. See example here: https://docs.spring.io/spring-batch/4.0.x/reference/html/readersAndWriters.html#readersAndWriters

How do you create a subclass of PropertySourcesPropertyResolver in spring 4?

I'm trying to figure out a way to store certain properties in an encrypted form while they are at rest, and have them transparently decrypted before the property is injected into any beans, whether they are using #Value or they are defined in xml by setting properties. We're not using spring-boot yet. The property file would look like this:
db_password={aes}some_encrypted_value
I can see in the logs where the PropertySourcesPropertyResolver gets the value for my property. It should be pretty simple to create my own implementation of the PropertySourcesPropertyResolver.getProperty method that looks for the "{aes}" prefix, decrypting it if necessary, but I can't figure out how to use my subclass in my application.
Does anyone have any idea how I can get spring to use my implementation instead of Springs?
I initially tried to use the PropertySourcesPlaceholderConfigurer that worked for me in Spring 3, but I couldn't figure out how to make it work in spring 4. I also couldn't get the newer PropertySourcesPlaceholderConfigurer to work either.
Can anyone point me in the right direction?
We did it as follows with Spring 4.0.3 RELEASE
public class MyPropertyConfigurer extends PropertyPlaceHolderConfigurer{
protected void convertProperties(Properties props){
Enumeration<?> propertyNames = props.propertyNames();
while(propertyNames.hasMoreElements()){
String propName = (String)propertyNames.nextElement();
String propValue = (String)props.getProperty(propName);
if(propName.indexOf("db_password") != -1){
setPropertyValue(props,propName,propValue);
}
}
}
private void setPropertyValue(Properties props,String propName,String propValue){
String decryptedValue = PasswordUtility.decrypt(propValue);
props.setProperty(propName,decryptedValue);
}
}
In xml, it was configured as below
<bean id="dbPropertyPlaceholder" class="mypackage.MyPropertyConfigurer">
<property name="locations">
<list>
<value>file:myProp.properties</value>
<list>
</property>
</bean>

Get a message converter bean in Spring boot

I am trying to instantiate a resolver from spring-cloud-aws-messaging, specifically the NotificationMessageArgumentResolver. The problem is that it takes a MessageConvertor as an argument. So, this is what I have so far:
private NotificationMessageArgumentResolver notificationMessageArgumentResolver() {
new NotificationMessageArgumentResolver(this.messageConvertor);
}
To get the messageConvertor, I have tried:
#Autowired
public MvcConfig(MessageConvertor messageConvertor) {}
#Autowired
public MvcConfig(MappingJackson2MessageConverter messageConvertor) {}
but I get the same error either ways no bean found. The documentation is simply asking to use the XML:
<mvc:annotation-driven>
<mvc:argument-resolvers>
<ref bean="notificationResolver" />
</mvc:argument-resolvers>
<aws-messaging:notification-argument-resolver id="notificationResolver" />
Which, according to the doc
registers three argument resolvers: NotificationStatusHandlerMethodArgumentResolver, NotificationMessageHandlerMethodArgumentResolver, and NotificationSubjectHandlerMethodArgumentResolver.
So, following the answer from How to use argument-resolvers using annotation in Spring boot?, I am able to get 2 of the 3 beans added, as they don't need any beans I cannot access, however I am not able to instantiate NotificationMessageArgumentResolver due to the lack of a MessageConvertor. I am expecting all my messages to come purely in JSON, so I do know exactly which MessageConvertor to use, which is the default one for JSON that ships with Spring Boot.
EDIT
The entire file, if anyone is interested: http://pastebin.com/tM471AEv
I wonder if you really need the NotificationMessageArgumentResolver as that is intended to be used when using messaging. As you can see it implements the HandlerMethodArgumentResolver from the org.springframework.messaging package.
I suspect that you want to use the NotificationMessageHandlerMethodArgumentResolver instead. Which is the HandlerMethodArgumentResolver for use with the web instead of messaging. Which is also registered when using <aws-messaging:notification-argument-resolver id="notificationResolver" />
I would also suggest to use the NotificationHandlerMethodArgumentResolverFactoryBean instead of 3 individual beans as that is also the class that is used internally by the namespace and annotation driven configuration.
Your configuration would look something like this.
#Bean
public NotificationHandlerMethodArgumentResolverFactoryBean notificationHandlerMethodArgumentResolverFactoryBean() {
return new NotificationHandlerMethodArgumentResolverFactoryBean();
}
#Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
argumentResolvers.add(notificationHandlerMethodArgumentResolverFactoryBean.getObject());
}

Define multiple URI for one <to .../> element with camel-spring

Having an Apache Camel route defined in Java, I can do something like this
from("stream:in?promptMessage=Enter something: ")
.loadBalance()
.to("uria", "urib")
and it works like a charme.
Trying this using a Spring context file doesn't work out:
<c:camelContext id="defaultContext">
<c:route id="defaultRoute">
<c:from uri="stream:in?promptMessage=Enter something: "/>
<c:loadBalance inheritErrorHandler="false">
<c:to uri="uria, urib"/>
</c:loadBalance>
<c:to uri="stream:out"/>
</c:route>
</c:camelContext>
Any idea, how i can set more than one uri per <c:to ... element? I do not want to have multiple <c:to ... elements. Is there any way, e.g. having a route factory passing the list?
What is the cause I want to achieve this: I'd like to inject a list of URIs from a configuration file passing them directly to the Camel route.
I'm using version 2.12.1 of Apache Camel.
Use a RouteBuilder class to create a route that reads URI's from somewhere.
Use contextScan to load the route builder class into spring camel context. Refer section Using contextScan on apache's site.
The RouteBuilder class shall be
#Component
public class MyRoute extends SpringRouteBuilder {
#Override
public void configure() throws Exception {
String URIs = // read all URI's from file or somewhere
from("direct:start")
.loadbalance()
.to(URIs);
}
}

mybatis 3.1 + sprinng 3.2 properties

We have 4 applications running on a Tomcat7 server. The existing applications work on Hibernate and Spring.
The backend is connected to a second database and some old schemas are kept here live. Each schema is called xxx_live and xxx_test.
When the Tomcat server starts, a JNDI property is set for the right environment.
Test
Local
Live
The properties are parsed on an extention of the PropertySourcesPlaceholderConfigurer class:
public class GenericPropertySourcesPlaceholderConfigurer extends PropertySourcesPlaceholderConfigurer {
private String application;
private String environment;
private static final String ENVIRONMENT = "environment";
public GenericPropertySourcesPlaceholderConfigurer(String application) throws IOException {
this.application = application;
this.environment = System.getProperty(ENVIRONMENT);
if (this.environment == null) {
this.environment = System.getenv().get(ENVIRONMENT);
}
initPropertySources();
}
/**
* setup default properties configuration
* Default configuration properties look like :
* app-global.properties
* app-environment.properties
* jndi properties
*/
private void initPropertySources() throws IOException {
MutablePropertySources propertySources = new MutablePropertySources();
propertySources.addLast(new ResourcePropertySource(new ClassPathResource(MessageFormat.format("properties/{0}-global.properties", application))));
propertySources.addLast(new ResourcePropertySource(new ClassPathResource(MessageFormat.format("properties/{0}/{1}.properties", environment, application))));
propertySources.addLast(new NotFailingJndiPropertySource("jndi"));
setPropertySources(propertySources);
setIgnoreResourceNotFound(false);
setIgnoreUnresolvablePlaceholders(true);
}
}
Now we're migrating everything to MyBatis. Is there a way to inject or parse these properties into my XML configuration?
Something like:
<select id="findAllUsers" parameterType="list" resultType="user">
SELECT * FROM ${mybatis.default_schema}.USER
</select>
Yes, Definitely you can pass this property.
The function declaration in DAO layer (JAVA Mapper for mybatis in spring) would be like
List<User> findAllUsers(#Param("schemaName") String schemaName)
And when you call this function pass the schema name as argument.
Few Suggestions (Assuming you are new to MyBatis)
You should rather configure your Property using spring's util tag in context.xml
i.e. <util:properties id="mailProps" location="classpath:mail.properties" />
Scan for Mappers & Autowire using spring (again in context.xml)
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.foo.bar" />
</bean>
Where com.foo.bar is package where you Java Interface's representing your XML are located.
This way You will actually be using spring's benefits i.e. DI / IOC
parameterType would be String or java.lang.String not list.
If you need further help / any doubts feel free to ask back.
HTH
Thanks.

Resources