Spring Data Neo4j - Exception when trying to use @Transactional annotation

I'm quite new with Spring Data and Neo4j, and there is something i don't understand about using the @Transactional annotation. It seems that i must declare an empty constructor for a class which i annotated one of its methods with @Transactional, and I also need to create an empty constructor for the node entities classes that the transaction will use... (and if i don't declare the empty constructors, i get an exception). But.. maybe i'm missing something. I'll show you an example, below is a code for example, which demonstrates what i'm talking about (Its a short spring-data-neo4j setup that gets things up and running):

My configuration class:

@Configuration
@ComponentScan(basePackages={"org.technion.socialrescue.core"})
@ImportResource("spring-data-context.xml")
@EnableTransactionManagement
public class DefaultApplicationConfig {
    @Bean(destroyMethod = "shutdown")
    public GraphDatabaseService graphDatabaseService() {
        return new EmbeddedGraphDatabase("target/graph.db");
    }
}

the spring-data-context.xml file:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:neo4j="http://www.springframework.org/schema/data/neo4j"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/data/neo4j http://www.springframework.org/schema/data/neo4j/spring-neo4j-2.0.xsd">


    <neo4j:config graphDatabaseService="graphDatabaseService" />
    <neo4j:repositories base-package="org.technion.socialrescue" />
</beans>

The class that hosts the method that is marked with @Transactional:

@Component("someClass")
public class SomeClass {

    public SomeObjectRepository someObjects;    

    @Autowired
    public SomeClass(SomeObjectRepository someOBjects) {
        this.someObjects = someOBjects;
    }

    @Transactional
    public void someMethod() {
        someObjects.save(new SomeObject("roy"));        
    }
}

the SomeObject class (which will be used as a node in the graph):

@NodeEntity
public class SomeObject {

    public SomeObject(String name) {
        this.name = name;
    }

    @GraphId
    private Long id;    

    @Indexed
    String name;
}

The SomeObjectRepository interface:

package org.technion.socialrescue.core;

import org.springframework.data.neo4j.repository.GraphRepository;

public interface SomeObjectRepository extends GraphRepository<SomeObject> {

}

and the code that launch the application:

public class Playground {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(DefaultApplicationConfig.class);
        SomeClass someClass = (SomeClass)context.getBean("someClass");
        someClass.someMethod();
        context.close();
    }
}

So, by running the code above, I'm getting the following exception:

Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'someClass' defined in file [C:\Users\t-rvelic\workspace\social-rescue\target\classes\org\technion\socialrescue\core\SomeClass.class]: Initialization of bean failed; nested exception is org.springframework.aop.framework.AopConfigException: Could not generate CGLIB subclass of class [class org.technion.socialrescue.core.SomeClass]: Common causes of this problem include using a final class or a non-visible class; nested exception is java.lang.IllegalArgumentException: Superclass has no null constructors but no arguments were given
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:527)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:456)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:294)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:225)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:291)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:607)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:932)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:479)
    at org.springframework.context.annotation.AnnotationConfigApplicationContext.<init>(AnnotationConfigApplicationContext.java:73)
    at org.technion.socialrescue.playground.Playground.main(Playground.java:13)
Caused by: org.springframework.aop.framework.AopConfigException: Could not generate CGLIB subclass of class [class org.technion.socialrescue.core.SomeClass]: Common causes of this problem include using a final class or a non-visible class; nested exception is java.lang.IllegalArgumentException: Superclass has no null constructors but no arguments were given
    at org.springframework.aop.framework.CglibAopProxy.getProxy(CglibAopProxy.java:217)
    at org.springframework.aop.framework.ProxyFactory.getProxy(ProxyFactory.java:111)
    at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.createProxy(AbstractAutoProxyCreator.java:477)
    at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.wrapIfNecessary(AbstractAutoProxyCreator.java:362)
    at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.postProcessAfterInitialization(AbstractAutoProxyCreator.java:322)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsAfterInitialization(AbstractAutowireCapableBeanFactory.java:407)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1461)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:519)
    ... 10 more
Caused by: java.lang.IllegalArgumentException: Superclass has no null constructors but no arguments were given
    at org.springframework.cglib.proxy.Enhancer.emitConstructors(Enhancer.java:721)
    at org.springframework.cglib.proxy.Enhancer.generateClass(Enhancer.java:499)
    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.create(Enhancer.java:285)
    at org.springframework.aop.framework.CglibAopProxy.getProxy(CglibAopProxy.java:205)
    ... 17 more

So i tried to follow the cause for this exception, and added an empty constructor for SomeClass, so it looks like this:

@Component("someClass")
public class SomeClass {

    public SomeObjectRepository someObjects;

    public SomeClass() {

    }   

    @Autowired
    public SomeClass(SomeObjectRepository someOBjects) {
        this.someObjects = someOBjects;
    }

    @Transactional
    public void someMethod() {
        someObjects.save(new SomeObject("roy"));        
    }
}

Then, i launched again my app, and got the following exception:

Exception in thread "main" org.springframework.dao.InvalidDataAccessApiUsageException: SomeObject: entity must have a no-arg constructor.; nested exception is java.lang.IllegalArgumentException: SomeObject: entity must have a no-arg constructor.
    at org.springframework.data.neo4j.support.Neo4jExceptionTranslator.translateExceptionIfPossible(Neo4jExceptionTranslator.java:43)
    at org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:58)
    at org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:213)
    at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:163)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204)
    at com.sun.proxy.$Proxy39.save(Unknown Source)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:317)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:183)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150)
    at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:96)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:260)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:94)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204)
    at com.sun.proxy.$Proxy40.save(Unknown Source)
    at org.technion.socialrescue.core.SomeClass.someMethod(SomeClass.java:23)
    at org.technion.socialrescue.core.SomeClass$$FastClassByCGLIB$$d9c3b9ef.invoke(<generated>)
    at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:698)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150)
    at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:96)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:260)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:94)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:631)
    at org.technion.socialrescue.core.SomeClass$$EnhancerByCGLIB$$d5a7b8cd.someMethod(<generated>)
    at org.technion.socialrescue.playground.Playground.main(Playground.java:17)
Caused by: java.lang.IllegalArgumentException: SomeObject: entity must have a no-arg constructor.
    at org.springframework.data.neo4j.support.mapping.AbstractConstructorEntityInstantiator$1.create(AbstractConstructorEntityInstantiator.java:87)
    at org.springframework.data.neo4j.support.mapping.AbstractConstructorEntityInstantiator.createEntityFromState(AbstractConstructorEntityInstantiator.java:56)
    at org.springframework.data.neo4j.support.mapping.Neo4jEntityPersister$CachedInstantiator.createEntityFromState(Neo4jEntityPersister.java:135)
    at org.springframework.data.neo4j.support.mapping.Neo4jEntityPersister$CachedInstantiator.createEntityFromState(Neo4jEntityPersister.java:122)
    at org.springframework.data.neo4j.support.mapping.Neo4jEntityConverterImpl.read(Neo4jEntityConverterImpl.java:86)
    at org.springframework.data.neo4j.support.mapping.Neo4jEntityPersister$CachedConverter.read(Neo4jEntityPersister.java:170)
    at org.springframework.data.neo4j.support.mapping.Neo4jEntityPersister.createEntityFromState(Neo4jEntityPersister.java:189)
    at org.springframework.data.neo4j.support.mapping.Neo4jEntityPersister.persist(Neo4jEntityPersister.java:244)
    at org.springframework.data.neo4j.support.mapping.Neo4jEntityPersister.persist(Neo4jEntityPersister.java:231)
    at org.springframework.data.neo4j.support.Neo4jTemplate.save(Neo4jTemplate.java:293)
    at org.springframework.data.neo4j.support.Neo4jTemplate.save(Neo4jTemplate.java:287)
    at org.springframework.data.neo4j.repository.AbstractGraphRepository.save(AbstractGraphRepository.java:109)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.executeMethodOn(RepositoryFactorySupport.java:333)
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:318)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:96)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:260)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:94)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:155)
    ... 28 more

So this time, i added an empty constructor for the SomeObject class, it looks like that:

@NodeEntity
public class SomeObject {

    public SomeObject() {

    }

    public SomeObject(String name) {
        this.name = name;
    }

    @GraphId
    private Long id;    

    @Indexed
    String name;
}

And then it worked...

But why it worked? why i had to add two empty constructors? I tried to google it, found nothing. I really want to know why it behaves like that... any help will be highly appreciated!

Thanks!

Answers


Your beans are being proxied by cglib to enable the transaction management. If I'm not mistaken, cglib needs a default constructor to be able to proxy your beans. You might opt for AspectJ to proxy your classes, so you don't need default constructors.

@EnableTransactionManagement(mode = AdviceMode.ASPECTJ)

Make sure AspectJ is on your classpath!


Need Your Help

SQL query to conditionally sum based on moving date window

sql postgresql case

I'm trying to figure out some sliding window stats on my users. I have a table with a user, and columns such as created_at and verified_at. For each month, I'd like to find out how many users

How do you get the current text contents of a QComboBox?

python pyqt pyqt4 python-2.6 qcombobox

using pyqt4 and python 2.6, i am using a qcombobox to provide a list of options. i am having problems with using the selected option. i have been able to use a signal to trigger a method when the o...

About UNIX Resources Network

Original, collect and organize Developers related documents, information and materials, contains jQuery, Html, CSS, MySQL, .NET, ASP.NET, SQL, objective-c, iPhone, Ruby on Rails, C, SQL Server, Ruby, Arrays, Regex, ASP.NET MVC, WPF, XML, Ajax, DataBase, and so on.