Aravind Yarram
Aravind Yarram

Reputation: 80176

Error while saving an entity with transient property with spring data neo4j

Why is spring-data looking at isCaptain even when I specified it as transient? From the documentation, the transient properties should be ignored. No error if I use a Boolean wrapper class

Exception

org.springframework.data.mapping.model.MappingException: Setting property isCaptain to null on Player [nodeId=1, name=null, firstName=null, lastName=null]
    at org.springframework.data.neo4j.support.mapping.SourceStateTransmitter.setProperty(SourceStateTransmitter.java:85)
    at org.springframework.data.neo4j.support.mapping.SourceStateTransmitter.copyEntityStatePropertyValue(SourceStateTransmitter.java:91)
    at org.springframework.data.neo4j.support.mapping.SourceStateTransmitter.access$000(SourceStateTransmitter.java:40)
    at org.springframework.data.neo4j.support.mapping.SourceStateTransmitter$1.doWithPersistentProperty(SourceStateTransmitter.java:54)
    at org.springframework.data.neo4j.support.mapping.SourceStateTransmitter$1.doWithPersistentProperty(SourceStateTransmitter.java:51)
    at org.springframework.data.mapping.model.BasicPersistentEntity.doWithProperties(BasicPersistentEntity.java:240)
    at org.springframework.data.neo4j.support.mapping.SourceStateTransmitter.copyPropertiesFrom(SourceStateTransmitter.java:51)
    at org.springframework.data.neo4j.support.mapping.Neo4jEntityConverterImpl.loadEntity(Neo4jEntityConverterImpl.java:100)
    at org.springframework.data.neo4j.support.mapping.Neo4jEntityConverterImpl.read(Neo4jEntityConverterImpl.java:92)
    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(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:601)
    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.invoke(TransactionInterceptor.java:110)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:155)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202)
    at com.sun.proxy.$Proxy38.save(Unknown Source)
    at com.aravind.avl.domain.PlayerRepositoryTest.firstNameExactMatchOnly(PlayerRepositoryTest.java:53)

ENTITY

@NodeEntity
public class Player
{
    @GraphId
    private Long nodeId;

    @GraphProperty
    @Indexed
    private String firstName;

    @GraphProperty
    @Indexed
    private String lastName;

    private transient boolean isCaptain;
}

JUNIT

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({ "/testContext.xml" })
@Transactional
public class PlayerRepositoryTest
{
    @Autowired
    PlayerRepository repo;

    Player p;

    @Before
    public void setUp()
    {
        p = new Player();
        p.setName("Aravind Yarram");
    }

    @Test
    public void firstNameFullTextSearch()
    {
        Player save = repo.save(p);
        assertNotNull(save);
        assertNotNull(p.getNodeId());

        EndResult<Player> players = repo.findAllByQuery("firstName", "A*");
        assertNotNull("Starts with first letter match", players.single());

        // TODO not supported
        // players = repo.findAllByQuery("firstName", "aravind");
        // assertNotNull("Lower-case mathch", players.single());
    }

    @Test
    public void firstNameExactMatchOnly()
    {
        Player save = repo.save(p);
        assertNotNull(save);
        assertNotNull(p.getNodeId());

        // either use domain specific method
        Player result = repo.findByPropertyValue("firstName", p.getFirstName());
        assertNotNull("findByPropertyValue should be used for EXACT matches", result);

        // or generic method
        result = repo.findPlayerByFirstName(p.getFirstName());
        assertNotNull("Exact mathch", result);
    }
}

Upvotes: 2

Views: 1076

Answers (1)

Aravind Yarram
Aravind Yarram

Reputation: 80176

@Transient as suggested by Sotirios Delimanolis works. I believe the transient keyword isn't honored because it can conflict with use-cases where Serialization is required. For e.g. you might want the isCaptain property to be available in web session but not required to be saved to the neo4j, my exact situation.

Upvotes: 1

Related Questions