Spring Integration service-activator referencing Hibernate JPA repository method - java

I'm trying to use a Hibernate JPA repository method as the method for a service-activator. The definition within the chain looks like the following.
<int:chain input-channel="bootstrapLineupCdsStart" output-channel="bootstrapLineupItemCdsStart">
<int:service-activator ref="lineupRepository" method="findByIntegrationStatusNew" />
<int:filter expression="!payload.isEmpty()" discard-channel="bootstrapLineupItemCdsStart"/>
<int:splitter expression="payload"/>
<int:service-activator ref="lineupServicePipeline" method="createLineup"/>
<int:aggregator/>
</int:chain>
The offending line is the first service-activator, specifically this line <int:service-activator ref="lineupRepository" method="findByIntegrationStatusNew" />
For the sake of completeness here is the repository class itself
#Repository( "lineupRepository" )
public interface LineupRepository extends JpaRepository<LineupEntity, Integer> {
#Query("select l from LineupEntity l where l.integrationStatus = 0")
List<LineupEntity> findByIntegrationStatusNew();
}
Now because of the magic of spring/hibernate I don't actually implement the findByIntegrationStatusNew myself; this is dynamically implemented by the framework at runtime. I also don't need to explicitly define the lineupRepository bean as the #Repository annotation handles this for me.
As a result of the above I get the following exeption.
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.integration.handler.MessageHandlerChain#9$child#0.handler': FactoryBean threw exception on object creation; nested exception is java.lang.IllegalArgumentException: Target object of type [class com.sun.proxy.$Proxy79] has no eligible methods for handling Messages.
Finally, I do have a work around in place that seems to get the job done; it is an obvious work around and I suspect shouldn't be necessary. The work around consists of creating a new bean, explicitly defining the bean in the context XML and calling that method instead of the method on repository. So my work around looks a bit like this; first the workaround's context looks like this instead.
<int:chain input-channel="bootstrapLineupCdsStart" output-channel="bootstrapLineupItemCdsStart">
<int:service-activator ref="lineupRepositoryService" method="findByIntegrationStatusNew" />
<int:filter expression="!payload.isEmpty()" discard-channel="bootstrapLineupItemCdsStart"/>
<int:splitter expression="payload"/>
<int:service-activator ref="lineupServicePipeline" method="createLineup"/>
<int:aggregator/>
</int:chain>
<bean id="lineupRepositoryService" class="com.mypackage.LineupRepositoryService"/>
Notice the first service-activator now references LineupRepositoryService instead of LineupRepository, and I also added a new bean definition.
Second in the work around, of course, I also defined a LineupRespositoryService class that looks like the following.
public class LineupRepositoryService {
#Autowired
private LineupRepository lineupRepository;
public List<LineupEntity> findByIntegrationStatusNew() {
return lineupRepository.findByIntegrationStatusNew();
}
}
The workaround works, but I'd rather do it the right way. So anyone know how I can get it to properly work or what is going on here?

#JeffreyPhillipsFreeman, we confirm with the test-cases that it is an issue from Spring Integration reflection method invocation perspective.
Need to fix it anyway: https://jira.spring.io/browse/INT-3820.
Mean while there is only a workaround like your service wrapper.

Related

which context.getBean to use when get the bean from spring

In the following link
http://docs.spring.io/spring-amqp/reference/html/quick-tour.html
It defined a bean in XML like
<rabbit:template id="amqpTemplate" connection-factory="connectionFactory"/>
Then in the calling code, it used
AmqpTemplate template = context.getBean(AmqpTemplate.class);
Why it used
context.getBean(AmqpTemplate.class);
instead of
context.getBean("amqpTemplate");
What's the getBean(AmqpTemplate.class) means? I can't find it defined by xml.
getBean()
is an overloaded method. You can call with the bean name or a bean type. Calling with the class returns the single instance of this class type. If there are more than one throws an exception. If there are none again throws an exception.
See here.
If you used context.getBean("amqpTemplate") you would need to cast the result to AmqpTemplate while getBean(AmqpTemplate.class) does it automatically. Note that getBean(AmqpTemplate.class) can only work if you have only one bean with AmqpTemplate class in the context

Spring 4 Webservice HTTP 500 - IllegalStateException: The mapped controller method class is not an instance of the actual controller bean

so I am working on a school project and I am trying to build a JSON Rest Webservice application. I am using Spring 4 and Hibernate 4 with Jackson 2.
I have a lot of hard times with this app, but now I have a problem I cannot overgo. I am using Cloudbees as my cloud service provider and from time to time (which is important to state, because it sometimes work and sometimes not!) I get a HTTP 500 error :/.
The best part is - I never had it locally.
It goes more or less like this:
HTTP Status 500 - Request processing failed; nested exception is java.lang.IllegalStateException: The mapped controller method class 'pl.lodz.pp.controllers.crud.impl.UserController' is not an instance of the actual controller bean instance 'com.sun.proxy.$Proxy47'. If the controller requires proxying (e.g. due to #Transactional), please use class-based proxying.
And I am so confused. I never get this locally and usually if I restart the application on cloud (one or more time) it will work for some time again.
I had made some errors, like
#Autowire
private ClassType variable
instead of
#Autowire
private ClassInterface variable
but I fixed them all. I am NOT USING #Transactional annotation anymore. At least not in my class. Maybe the GenericDao have it somewhere (https://code.google.com/p/hibernate-generic-dao/) but I never had this problem before.
Transaction management:
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
Please, find the full code here:
https://github.com/atais/PP-JSON
Bottom line
I am not using #Transactional and I inject everything with the Interface type. So what am I possibly doing wrong? And what's the best - it works sometimes, but sometimes I get this error :/
The only thing you need to do is to add
#EnableAspectJAutoProxy(proxyTargetClass = true)
to your Spring Configuration.
In many cases the framework applies for your classes some proxying mechanisms: TX, Cache, Async etc. - depends on annotations, which you are using on your classes or its methods.
So it is good practice to introduce for those classes interfaces and use exactly that contract, not classes.
I understand that it looks like overhead for all #Service classes, but introduce interfaces at least for those classes which use some AOP aspects
I got the same exception when i implemented a interface (controller extends x implements interface) in my controller. Removing the interface solved the problem. I suspect implementing a specific interface is not supported for controllers.

Spring BeanNotOfRequiredTypeException

I have bean like this :
<bean id="myBean" class="com.mypackage.MyClass" scope="session">
</bean>
here is the class declaration :
MyClass extends MySuperClass implements MyInterface<A>
MySuperClass extends GenericClass<A>
Later I try to do this :
applicationContext.getBean("myBean", GenericClass.class);
And I get this error :
org.springframework.beans.factory.BeanNotOfRequiredTypeException: Bean named 'myBean' must be of type [com.mypackage.GenericClass], but was actually of type [com.sun.proxy.$Proxy118]
I solved it by adding :
<aop:scoped-proxy />
inside my bean declaration but I like to understand what I am doing and in this case I don't.
Could you explain me why I am getting this exception and why adding <aop:scoped-proxy /> solved it ?
thanks !
By adding <aop:scoped-proxy/> I believe you are telling Spring to use a smart object proxy rather than just a plain JDK interface proxy. Basically your proxy object is backed by your actual object so that when you pass it around it looks just like your regular object. It sounds like a compromise between using AspectJ loadtime weaving and plain JDK proxies. Have a read of what the equivalent annotation does here
EDIT 1: Actually it looks like using CGLib (AspectJ) based proxies is the default option there. Thats probably what fixed your problem.

Spring injecting or autowiring datasource bean to class

this may be a very novice question, but I have searched and either I have a large gap in my understanding or am doing something incorrectly that I cannot figure out.
In my context file here is an excerpt
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${datasource.driverClassName}" />
<property name="url" value="${datasource.url}" />
<property name="username" value="${datasource.username}" />
<property name="password" value="${datasource.password}" />
</bean>
<bean id="myBeanOne" class="a.b.c.myBeanOne">
<property name="dataSource" ref="dataSource" />
</bean>
Now in myBeanOne I have:
private DataSource dataSource;
private JdbcTemplate jdbcTemplate;
#Autowired
public void setDataSource (DataSource dataSource) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
}
public void myMethod() {
String sql = "'My generic SQL update query'";
try {
this.jdbcTemplate.update(sql);
} catch (org.springframework.dao.EmptyResultDataAccessException ex) {
}
System.exit(0);
}
when I try to execute this on the line where setDataSource is invoked I get this error:
ERROR org.springframework.integration.handler.LoggingHandler
org.springframework.integration.MessageHandlingException:
java.lang.NullPointerException
on the line: this.jdbcTemplate.update(sql);
I have tried maybe ten different configurations to get this to work, but I cannot seem to do it. Any assistance is appreciated, thank you.
Edit: as per Luiggi's comment:
//in yet another classes run method
myBeanOne bOne = SomeOtherClass.create(); //just returns new myBeanOne
bOne.myMethod();
Neither SomeOtherClass or this class are classified as beans in the context or have any presence in the context.
I know that this is a very basic question but I am struggling with it.
Thank you for your patience.
As noted in comments, the problem is that you're manually creating the bean instead of letting Spring container create it. Basically, you're doing this:
new MyBeanOne()
So Spring container can't inject any of the fields you have configured thus being null e.g. jdbcTemplate field. There are some solutions to this:
Convert your SomeOtherClass into a bean managed by Spring container and let it inject the MyBeanOne instance (probably using #Autowired annotation).
If latter approach can't be done since you need to manually create the bean, you can create the bean manually as shown here: How to create spring beans dynamically?
But this implementation makes you hardcode somewhere the spring config file name and use it in your code. So, a better approach would be option 3.
Look at this solution: Creating New Spring Beans on Demand, where you create a client abstract class with a method that Spring will implement to retrieve a new instance of your Spring managed bean.
I found another way to handle this by using #Configurable annotation. By decorating your bean with this annotation, you can create a new instance of the bean on demand and Spring will manage the injection of Spring managed beans for you. But to achieve this, Spring needs to use aspects behind the scenes and you should activate usage of aspects for your project. The explanation is quite long, so I provide links that explain in depth this solution:
Spring Framework: 7.8 Using AspectJ with Spring applications
Using Spring's #Configurable in three easy steps
Note that in order to enable this feature, you have to add a java agent when starting the JVM that will weave the class at runtime using aspects.
NullPointerException on the line: this.jdbcTemplate.update(sql);
If the NPE is actually on that line, then this.jdbcTemplate is obviously null. If this is true then either:
The setDataSource(...) method is not being called in Spring, possibly because the #Autowired is not right somehow. It would be easy to add a System.out.println(...) or put a debugging breakpoint in setDataSource to see if it is being called.
If it is being called then maybe there are more than one instance of a.b.c.myBeanOne? Are you for sure getting the instance being called from another class from the Spring context? Put a breakpoint in setDataSource and notice the this object reference id. Then put a breakpoint on the this.jdbcTemplate.update(...) line and make sure that the this reference-id is the same.

Are there Compound property values in Spring

I read about Compound property names in the "The Spring Framework (2.5) - Reference Documentation - chapter 3.3.2.7"
Can i use the same concept to set values of properties? Can i use a compound string as a value expression?
<bean id="service1" class="a.b.c.Service1Impl" scope="prototype">
<property name="service2" ref="service2"/>
<property name="service2.user" value="this-service1-instance.user"/>
</bean>
<bean id="service2" class="a.b.c.Service2Impl" scope="prototype">
...
</bean>
User is a property of a.b.c.Service1Impl which is not in control of Spring. I want to forward this property to a.b.c.Service2Impl.
Rather than use a plain old factory bean, rather use a factory method to create the bean of the property and then inject that result...
iow
in your case, it would look something like this...
<!-- the bean to be created via the factory bean -->
<bean id="exampleBean"
factory-bean="serviceLocator"
factory-method="createInstance"/>
So the bean of id is created by calling createInstance on bean serviceLocator.
Now spring does not support nested properties out of the box, though you could look at creating a custom editors which might provide that support - possible but tricky. Possibly not worth the effort.
One mechanism you could look at using is nesting using the factory-bean factory-method technique...
Something like:
<bean id="c" class="C" />
<bean id="b" factory-bean="c" factory-method="getB"/>
<bean id="a" factory-bean="b" factory-method="getA"/>
This will effectively expose: a.b.c where C has a method getB and A has a method getB
I had to do something similar, and I'm afraid it's not possible. I had to write a [FactoryBean][1] to expose the property.
It would look something like this:
public class UserFactory implements BeanFactory {
private Service2 service2;
// ... setter and getter for service2
public Object getObject() {
return getService2().getUser();
}
public Class getObjectType() {
return User.class;
}
public boolean isSingleton() {
// Since it's a prototype in your case
return false;
}
}
Come to think of it, in your case, you'd probably define the factory itself as a prototype, in which case your isSingleton() may return true, you'll need to play around with this a little bit.
Spring's XML wiring syntax supports lists, maps and properties objects, and you can create other 'data' objects via property editors.
Edit: (Oh I see what you are asking.) I think that the answer is no. I don't recall having seen any mention of calling getters on a bean or non-bean object in the Spring documentation, let alone a syntax for doing this in the wiring file. It tends to go against the grain. Spring wiring is declarative, and calling a getter would lead to patterns that are bordering on procedural.

Categories