Unable to create Spring AOP aspect on Spring Data JPA Repository when CGLIB proxies are used - spring-data

I'm trying to apply an aspect on a Spring Data JPA Repository and it works fine with default Spring AOP config
#EnableAspectJAutoProxy
(when Spring uses standard Java interface-based proxies).
However, when I switch to CGLIB proxies:
#EnableAspectJAutoProxy(proxyTargetClass = true)
I get this exception:
Caused by: org.springframework.aop.framework.AopConfigException: Could not generate CGLIB subclass of class [class com.sun.proxy.$Proxy59]:
Looks like Spring tries to wrap a CGLIB proxy on a repository class, which is already a CGLIB proxy (generated by Spring Data) and fails.
Any ideas how to make it work?
My Spring Data Repository:
import org.springframework.data.jpa.repository.JpaRepository;
public interface DummyEntityRepository extends JpaRepository<DummyEntity, Integer> {
}
and the aspect:
#Aspect
public class DummyCrudRepositoryAspect {
#After("this(org.springframework.data.repository.CrudRepository)")
public void onCrud(JoinPoint pjp) {
System.out.println("I'm there!");
}
}

Related

Unable to autowire the Processor after adding User-defined message converters

On Finchley.SR2, here is the code
#Configuration
#EnableAutoConfiguration
#SpringBootApplication
#EnableBinding(Processor.class)
#RestController
public class Application {
private static Logger log = LoggerFactory.getLogger(Application.class);
#Autowired
private Processor processor;
#Autowired
MappingJackson2MessageConverter testConverter;
#Bean
#StreamMessageConverter
MappingJackson2MessageConverter createTestConverter(){
return new MappingJackson2MessageConverter();
}
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
When I start up, I got
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.cloud.stream.messaging.Processor' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
But if I take out #StreamMessageConverter, the Processor can be autowired successfully.
What should I do to keep my customized message converter and autowired Processor at the same time? Thanks!
There is a lot going on there, so lets try to parse it put. . .
First question, why do you need to autowire the following?
#Autowired
private Processor processor;
You, generally don't need to interact with Processor directly since it is used bt the framework to provide a delegation/connectivity model between remote destinations exposed by the binders and your message handlers
Further more, your actual issue is related to a lifecycle which may be a minor yet harmless bug on our end and probably relates to configuring and autowiring Processor in the same configuration class.
Second:
#Configuration
#EnableAutoConfiguration
#SpringBootApplication
You only need one
#SpringBootApplication
Third:
Why do you need to configure MappingJackson2MessageConverter? Content type conversion is a transparent feature of he framework and while we do provide an ability to configure custom message converters, the one you are configuring is already configured by the framework and in fact is the first in the stack of seven pre-configured message converters
The final question:
What is it that your are trying to do? Can you explain your use case?

Spring data entities in different packages

I am new to spring and want to use the following project structure in spring boot application.
Different package for each type of entity and its corresponding repository implementation.
A Package for repository configuration
*
**com.demo.Customer**
Customer.java
CustomerRepository.java
Application.java
**com.demo.Order**
Order.java
OrderRepository.java
**com.demo.config**
ApplicationConfig.java
CustomerConfig.java
OrderConfig.java
CustomerConfig.java
import com.demo.cstore.core.Customer;
#Configuration
#EnableJpaRepositories(basePackageClasses = Customer.class)
public class CustomerConfiguration {
}
Application.java
#SpringBootApplication
#ComponentScan(basePackages = {"com.demo.order"}) //inject repository from other packages
public class Application {
private static final Logger log = LoggerFactory.getLogger(Application.class);
public static void main(String[] args) {
SpringApplication.run(Application.class);
}
After compiling and running the application, only customer entity is created. Is that because application file just recognizes customer entity as it exists in the same package com.demo.Customer. How can Order entity be injected and and an entity is created?
The EnableJpaRepositories annotation accepts an array of Strings basePackages here you can add all packages where your entities are:
#EnableJpaRepositories(basePackages={"com.demo.order"
,"com.demo.customer"
,"com.demo.config"})
That must be enough. Hope this helps.
you don't need to use #ComponentScan.
According to documentation
The #SpringBootApplication annotation is equivalent to using
#Configuration, #EnableAutoConfiguration and #ComponentScan with their
default attributes
so you can just use #SpringBootApplication on your main class which is located in the base package of your packages hierarchy and you will be fine.
you can too refer to this link to know about how to structure your code and main class location
http://docs.spring.io/spring-boot/docs/current/reference/html/using-boot-structuring-your-code.html
and this the API documentation for #SpringBootApplication
https://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/autoconfigure/SpringBootApplication.html
In our application we customize LocalContainerEntityManagerFactoryBean, so had to set the packages to scan there eg.:
LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
factory.setDataSource(dataSource);
factory.setPackagesToScan("com.example.multitenancy.test.entity");

Autowiring issues with a class in Spring data Mongo repository

For a variety of reasons, I ended up using spring boot 1.2.0 RC2.
So a spring data mongo application that worked fine in spring boot1.1.8 is now having issues. No code was changed except for the bump to spring boot 1.2.0 RC2. This is due to the snapshot version of spring cloud moving to this spring boot version.
The repository class is as follows
#Repository
public interface OAuth2AccessTokenRepository extends MongoRepository<OAuth2AuthenticationAccessToken, String> {
public OAuth2AuthenticationAccessToken findByTokenId(String tokenId);
public OAuth2AuthenticationAccessToken findByRefreshToken(String refreshToken);
public OAuth2AuthenticationAccessToken findByAuthenticationId(String authenticationId);
public List<OAuth2AuthenticationAccessToken> findByClientIdAndUserName(String clientId, String userName);
public List<OAuth2AuthenticationAccessToken> findByClientId(String clientId);
}
This worked quite well before the bump in versions and now I see this in the log.
19:04:35.510 [main] DEBUG o.s.c.a.ClassPathBeanDefinitionScanner - Ignored because not a concrete top-level class: file [/Users/larrymitchell/rpilprojects/corerpilservicescomponents/channelMap/target/classes/com/cisco/services/rpil/mongo/repository/oauth2/OAuth2AccessTokenRepository.class]
I do have another mongo repository that is recognized but it was defined as a class implementation
#Component
public class ChannelMapRepository { ... }
This one is recognized (I defined it as a implementation class as a workaround for another problem I had). This class is recognized and seems to work fine.
19:04:35.513 [main] DEBUG o.s.c.a.ClassPathBeanDefinitionScanner - Identified candidate component class: file [/Users/larrymitchell/rpilprojects/corerpilservicescomponents/channelMap/target/classes/com/cisco/services/rpil/services/Microservice.class]
Anyone have an idea why? I looked up the various reasons for why component scanning would not work and nothing lends itself to my issue.
Try removing the #Repository annotation? Worked for me. This was an issue in Github as well.

Cglib proxy errors using and Spring Data when moving from Spring XD M5 to Release 1.0.0

We're moving a number of batch jobs from Spring XD M5 to the 1.0.0 release.
When creating and deploying the jobs, we are hitting an issue with cglib proxy functionality when autowiring Spring Data repositories (for Neo4J in this case).
The tail end of the stack trace:
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'datasetRepository': Post-processing of FactoryBean's singleton object failed; nested exception is org.springframework.aop.framework.AopConfigException: Could not generate CGLIB subclass of class [class
com.sun.proxy.$Proxy112]: Common causes of this problem include using a final class or a non-visible class; nested exception is java.lang.IllegalArgumentException: Cannot subclass final class class com.sun.proxy.$Proxy112
at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.getObjectFromFactoryBean(FactoryBeanRegistrySupport.java:116)
at org.springframework.beans.factory.support.AbstractBeanFactory.getObjectForBeanInstance(AbstractBeanFactory.java:1512)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:313)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.java:1017)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:960)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:858)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:480)
... 54 more
Caused by: org.springframework.aop.framework.AopConfigException: Could not generate CGLIB subclass of class [class com.sun.proxy.$Proxy112]: Common causes of this problem include using a final class or a non-visible class; nested exception is java.lang.IllegalArgumentException: Cannot subclass final
class class com.sun.proxy.$Proxy112
at org.springframework.aop.framework.CglibAopProxy.getProxy(CglibAopProxy.java:212)
at org.springframework.aop.framework.ProxyFactory.getProxy(ProxyFactory.java:109)
at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.createProxy(AbstractAutoProxyCreator.java:494)
at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.wrapIfNecessary(AbstractAutoProxyCreator.java:379)
at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.postProcessAfterInitialization(AbstractAutoProxyCreator.java:339)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsAfterInitialization(AbstractAutowireCapableBeanFactory.java:421)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.postProcessObjectFromFactoryBean(AbstractAutowireCapableBeanFactory.java:1698)
at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.getObjectFromFactoryBean(FactoryBeanRegistrySupport.java:113)
... 61 more
Caused by: java.lang.IllegalArgumentException: Cannot subclass final class class com.sun.proxy.$Proxy112
at org.springframework.cglib.proxy.Enhancer.generateClass(Enhancer.java:446)
at org.springframework.cglib.transform.TransformingClassGenerator.generateClass(TransformingClassGenerator.java:33)
at org.springframework.cglib.core.DefaultGeneratorStrategy.generate(DefaultGeneratorStrategy.java:25)
at org.springframework.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:216)
at org.springframework.cglib.proxy.Enhancer.createHelper(Enhancer.java:377)
at org.springframework.cglib.proxy.Enhancer.createClass(Enhancer.java:317)
at org.springframework.aop.framework.ObjenesisCglibAopProxy.createProxyClassAndInstance(ObjenesisCglibAopProxy.java:57)
at org.springframework.aop.framework.CglibAopProxy.getProxy(CglibAopProxy.java:202)
... 68 more
The Spring Data repository interface is annotated with #Repository as follows:
#Repository
public interface DatasetRepository extends GraphRepository<Dataset>
{
public Dataset findOneById(String id);
public Dataset findOneByName(String name);
}
And the corresponding autowired attribute in our bean class which triggers the exception:
#Autowired
private DatasetRepository datasetRepo;
The bean itself is defined in our XD job XML as follows:
<bean id="myBean" class="com.mycompany.MyBean"/>
And the configuration bean (component scanned in the job cfg XML):
#Configuration
#EnableNeo4jRepositories({ "com.mycompany.repositories" })
public class CustomNeo4jConfiguration implements InitializingBean
The versions of Spring Data Neo4J which we deploy into the XD lib folder are as follows:
spring-data-neo4j : 3.2.0.RELEASE
spring-data-neo4j-rest : 3.2.0.RELEASE
The setup is all on a dev PC (for now) with XD running in distributed mode:
redis server
Zookeeper server (1x)
Oracle job repository (local XE instance for now)
1x admin and 1x container
Any help around configuration of the job, Spring Data repository or XD container would be much appreciated.
Thanks
Remove the #Repository annotation on your GraphRepository and you should be fine. Don't forget to enable component scanning.

JTA controlled transactions in JBoss AS7 using EclipseLink, Transaction is required

Environment
Application server: JBoss AS7 (7.1.1 Final)
JPA implementation: EclipseLink (2.4.1)
OS: Windows 7 DB: PostgreSQL 8.4
Update 2, solved
The problem was that i instantiated the AccountService class instead of injecting it using #EJB. After fixing that EntityManager was inected correctly in the service and a transaction was available when doing em.persist(account);
Update
I made a minimal project that shows my problems. Posted to Github:
https://github.com/gotling/jboss-eclipselink-problem
I have two problems that are probably related and due to me not understanding the use of EJB's correct.
I can not get EnityManager to be injected in AccountService.java in persistance JAR, resulting in NullPointerException.
If sending EntityManager in constructor to AccountService no tranasaction is found when doing em.persist.
Project structure
EJB
lib/persistanceunit.jar
web-service.war
Problem
I'm trying to get JBoss to manage transactions in my Java EE service. Problem is that EclipseLink does not seem to pick up the transaction managed by JBoss when trying to persist an entity.
I have followed the guide https://community.jboss.org/wiki/HowToUseEclipseLinkWithAS7 (Alternative 1 and Alternative 2 Step 4) on how to configure JBoss with EclipseLink.
Setup
WAR
Entity manager is injected like this in web-service.war:
#WebService(....)
public class NotificationConsumerImpl implements NotificationConsumer {
#PersistenceContext(unitName="foo")
EntityManager em;
public void notify(Notify notify) {
AccountService accountService = new AccountService(em);
accountService.create(notify);
}
}
There is actually a controller class between the class above and the service class, where transformation of the Account object is done, removed it to shorten code.
Persistance Unit
Entity is created like this
AccountService.java in persistanceunit.jar
#Stateless
public class AccountService {
private EntityManager em;
public AccountService(EntityManager em) {
this.em = em;
}
public void create(Account account) {
em.persist(account);
}
}
Stack trace
When calling a WS that should persist the Account entity I get an exception on em.persist(account);
...
Caused by: javax.persistence.TransactionRequiredException: JBAS011469: Transaction is required to perform this operation (either use a transaction or extended persistence context)
at org.jboss.as.jpa.container.AbstractEntityManager.transactionIsRequired(AbstractEntityManager.java:692) [jboss-as-jpa-7.1.1.Final.jar:7.1.1.Final]
at org.jboss.as.jpa.container.AbstractEntityManager.persist(AbstractEntityManager.java:562) [jboss-as-jpa-7.1.1.Final.jar:7.1.1.Final]
at se.magos.service.AccountService.create(AccountService.java:50) [persistenceunit-0.0.1-SNAPSHOT.jar:]
Questions
I've enabled Trace logging. Should not id.au.ringerc.as7.eclipselinkpersistence be visible in the log?
Is it somehow possible to get the EntityManager injected inside the service class inside the persistanceunit.jar?
In which JBoss / EclipseLink version should this wor out of the box?
You should annotate the bean with #TransactionManagement(TransactionManagementType.CONTAINER) and the create method with #TransactionAttribute(TransactionAttributeType.REQUIRED).
The first annotation is required in order to let the application server know that transactions are managed by the container, the latter to let the method start a transaction, if there is no current one, as soon as it is invoked.
The problem was that AccountService class was instantiated instead of injected using #EJB annotation. After fixing that EntityManager was injected correctly in the service and a transaction was available when doing em.persist(account);
Before
#WebService(....)
public class NotificationConsumerImpl implements NotificationConsumer {
#PersistenceContext(unitName="foo")
EntityManager em;
public void notify(Notify notify) {
AccountService accountService = new AccountService(em);
accountService.create(notify);
}
}
After
#WebService(....)
public class NotificationConsumerImpl implements NotificationConsumer {
#PersistenceContext(unitName="foo")
EntityManager em;
#EJB
AccountService accountService;
public void notify(Notify notify) {
accountService.create(notify);
}
}