New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Serialized predicate causes issues with ConstImpl cache #481

Closed
jotomo opened this Issue Aug 22, 2013 · 9 comments

Comments

Projects
None yet
2 participants
@jotomo

jotomo commented Aug 22, 2013

Im' using QueryDSL 2.9.0 with Spring Data JPA 1.3.4.

I have a client which contstructs a predicate, like this: 'QAdress.adress.name.eq("test")'. This is then serialized, send over the wire to the server and deserialized. The serialization process itself is fine and does no harm to the predicate. However, executing this query on the server (using Spring Data JPA, although this is definately not a relevant factor), I get an exception "Undeclared path 'adress'. Add this path as a source to the query to be able to reference it.". I checked the source of the exception, ValidatingVisitor.visit(Path<?> expr, Void context). This method checks if the root path of the predicate (adress) is known, more precisely, if the field 'known' contains the root of the expression (adress again). Where 'known' is a hashmap and hence uses hashcodes to determine if it contains an object. The hashcode is generated using HashCodeVisitor, which uses the metadata (PathType, parent and expression) to generate a hashcode. The 'known' field does contain an entry 'adress'. I compared this with the predicate; PathType is VARIABLE, parent is null and expression is a ConstantImpl with the value 'adress'. However, the ConstantImpl in 'known' is a different object than the one in the predicate, which makes me believe they have different hashcodes, and the cause why I get the exception. I haven't debugged further, but I'd suspect that caching may have to do with this, since the predicate was instanciated on the client, hence in a different JVM than on the server side (predicate execution and serialization works without problems in a unit test on the same JVM). As QueryDSL supports serialization AFAIK, this scenario should be supported too, right?

timowest added a commit that referenced this issue Aug 22, 2013

@timowest

This comment has been minimized.

Show comment
Hide comment
@timowest

timowest Aug 22, 2013

Member

The latest version of Querydsl doesn't have a String constant cache anymore. Is upgrade to a newer Querydsl version an option for you?

I also verified that local serialization/deserialization works properly with a test.

Member

timowest commented Aug 22, 2013

The latest version of Querydsl doesn't have a String constant cache anymore. Is upgrade to a newer Querydsl version an option for you?

I also verified that local serialization/deserialization works properly with a test.

@jotomo

This comment has been minimized.

Show comment
Hide comment
@jotomo

jotomo Aug 23, 2013

I upgraded to Spring Data JPA 1.4.0.RC1 (first version to support QueryDSL 3.2.2). The bogus source message is gone :-) Thanks Timo!

jotomo commented Aug 23, 2013

I upgraded to Spring Data JPA 1.4.0.RC1 (first version to support QueryDSL 3.2.2). The bogus source message is gone :-) Thanks Timo!

@jotomo jotomo closed this Aug 23, 2013

@jotomo

This comment has been minimized.

Show comment
Hide comment
@jotomo

jotomo Aug 23, 2013

Okay, so maybe that's not the whole story ...
The predicate can be executed now with the source as requested, however, I now get an error, but only for the very first request. All subsequent requests are fine:

15:57:08.228 [tomcat-http--3] INFO  d.n.i.e.b.s.domain.EntitiesService - Got search predicate: containsIc(standort.adresse.name1,Wellpappenwerk)
15:57:08.322 [tomcat-http--3] ERROR d.n.i.e.b.w.c.AbstractController - Unhandled exception
[Spring exception removed]
Caused by: java.lang.IllegalArgumentException: Got no pattern for null
    at com.mysema.query.support.SerializerBase.visitOperation(SerializerBase.java:287) ~[querydsl-core-3.2.2.jar:na]
    at com.mysema.query.jpa.JPQLSerializer.visitOperation(JPQLSerializer.java:395) ~[querydsl-jpa-3.2.2.jar:na]
    at com.mysema.query.support.SerializerBase.visit(SerializerBase.java:246) ~[querydsl-core-3.2.2.jar:na]
    at com.mysema.query.support.SerializerBase.visit(SerializerBase.java:42) ~[querydsl-core-3.2.2.jar:na]
    at com.mysema.query.types.OperationImpl.accept(OperationImpl.java:91) ~[querydsl-core-3.2.2.jar:na]
    at com.mysema.query.support.SerializerBase.handle(SerializerBase.java:102) ~[querydsl-core-3.2.2.jar:na]
    at com.mysema.query.jpa.JPQLSerializer.serialize(JPQLSerializer.java:208) ~[querydsl-jpa-3.2.2.jar:na]
    at com.mysema.query.jpa.JPAQueryBase.buildQueryString(JPAQueryBase.java:64) ~[querydsl-jpa-3.2.2.jar:na]
    at com.mysema.query.jpa.JPAQueryBase.toCountRowsString(JPAQueryBase.java:236) ~[querydsl-jpa-3.2.2.jar:na]
    at com.mysema.query.jpa.impl.AbstractJPAQuery.count(AbstractJPAQuery.java:80) ~[querydsl-jpa-3.2.2.jar:na]
    at org.springframework.data.jpa.repository.support.QueryDslJpaRepository.findAll(QueryDslJpaRepository.java:114) ~[spring-data-jpa-1.4.0.RC1.jar:na]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.7.0_21]
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) ~[na:1.7.0_21]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.7.0_21]
    at java.lang.reflect.Method.invoke(Method.java:601) ~[na:1.7.0_21]
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.executeMethodOn(RepositoryFactorySupport.java:333) ~[spring-data-commons-1.6.0.RC1.jar:na]
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:318) ~[spring-data-commons-1.6.0.RC1.jar:na]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172) ~[spring-aop-3.2.4.RELEASE.jar:3.2.4.RELEASE]
    at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:96) ~[spring-tx-3.2.4.RELEASE.jar:3.2.4.RELEASE]
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:260) ~[spring-tx-3.2.4.RELEASE.jar:3.2.4.RELEASE]
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:94) ~[spring-tx-3.2.4.RELEASE.jar:3.2.4.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172) ~[spring-aop-3.2.4.RELEASE.jar:3.2.4.RELEASE]
    at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:155) ~[spring-tx-3.2.4.RELEASE.jar:3.2.4.RELEASE]
    ... 52 common frames omitted

The predicate in this example is a bit different, but that's not the issue, I've tested it with the original predicate too, the deciding factor is that it's the first time a predicate is executed server-side.
I already spend days hunting down the original issue, so any hint would be greatly appreciated. If you need more info, let me know what.

jotomo commented Aug 23, 2013

Okay, so maybe that's not the whole story ...
The predicate can be executed now with the source as requested, however, I now get an error, but only for the very first request. All subsequent requests are fine:

15:57:08.228 [tomcat-http--3] INFO  d.n.i.e.b.s.domain.EntitiesService - Got search predicate: containsIc(standort.adresse.name1,Wellpappenwerk)
15:57:08.322 [tomcat-http--3] ERROR d.n.i.e.b.w.c.AbstractController - Unhandled exception
[Spring exception removed]
Caused by: java.lang.IllegalArgumentException: Got no pattern for null
    at com.mysema.query.support.SerializerBase.visitOperation(SerializerBase.java:287) ~[querydsl-core-3.2.2.jar:na]
    at com.mysema.query.jpa.JPQLSerializer.visitOperation(JPQLSerializer.java:395) ~[querydsl-jpa-3.2.2.jar:na]
    at com.mysema.query.support.SerializerBase.visit(SerializerBase.java:246) ~[querydsl-core-3.2.2.jar:na]
    at com.mysema.query.support.SerializerBase.visit(SerializerBase.java:42) ~[querydsl-core-3.2.2.jar:na]
    at com.mysema.query.types.OperationImpl.accept(OperationImpl.java:91) ~[querydsl-core-3.2.2.jar:na]
    at com.mysema.query.support.SerializerBase.handle(SerializerBase.java:102) ~[querydsl-core-3.2.2.jar:na]
    at com.mysema.query.jpa.JPQLSerializer.serialize(JPQLSerializer.java:208) ~[querydsl-jpa-3.2.2.jar:na]
    at com.mysema.query.jpa.JPAQueryBase.buildQueryString(JPAQueryBase.java:64) ~[querydsl-jpa-3.2.2.jar:na]
    at com.mysema.query.jpa.JPAQueryBase.toCountRowsString(JPAQueryBase.java:236) ~[querydsl-jpa-3.2.2.jar:na]
    at com.mysema.query.jpa.impl.AbstractJPAQuery.count(AbstractJPAQuery.java:80) ~[querydsl-jpa-3.2.2.jar:na]
    at org.springframework.data.jpa.repository.support.QueryDslJpaRepository.findAll(QueryDslJpaRepository.java:114) ~[spring-data-jpa-1.4.0.RC1.jar:na]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.7.0_21]
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) ~[na:1.7.0_21]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.7.0_21]
    at java.lang.reflect.Method.invoke(Method.java:601) ~[na:1.7.0_21]
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.executeMethodOn(RepositoryFactorySupport.java:333) ~[spring-data-commons-1.6.0.RC1.jar:na]
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:318) ~[spring-data-commons-1.6.0.RC1.jar:na]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172) ~[spring-aop-3.2.4.RELEASE.jar:3.2.4.RELEASE]
    at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:96) ~[spring-tx-3.2.4.RELEASE.jar:3.2.4.RELEASE]
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:260) ~[spring-tx-3.2.4.RELEASE.jar:3.2.4.RELEASE]
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:94) ~[spring-tx-3.2.4.RELEASE.jar:3.2.4.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172) ~[spring-aop-3.2.4.RELEASE.jar:3.2.4.RELEASE]
    at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:155) ~[spring-tx-3.2.4.RELEASE.jar:3.2.4.RELEASE]
    ... 52 common frames omitted

The predicate in this example is a bit different, but that's not the issue, I've tested it with the original predicate too, the deciding factor is that it's the first time a predicate is executed server-side.
I already spend days hunting down the original issue, so any hint would be greatly appreciated. If you need more info, let me know what.

@jotomo jotomo reopened this Aug 23, 2013

@timowest

This comment has been minimized.

Show comment
Hide comment
@timowest

timowest Aug 23, 2013

Member

This looks like a bug in the deserialization of OperationImpl. I will see how it could be fixed.

Member

timowest commented Aug 23, 2013

This looks like a bug in the deserialization of OperationImpl. I will see how it could be fixed.

timowest added a commit that referenced this issue Aug 23, 2013

@timowest

This comment has been minimized.

Show comment
Hide comment
@timowest

timowest Aug 23, 2013

Member

Could you test with the latest SNAPSHOT from here https://oss.sonatype.org/content/repositories/snapshots/

It looks like some optimization I did for Expression creation and comparison didn't work in the case when serialized expressions are used.

Member

timowest commented Aug 23, 2013

Could you test with the latest SNAPSHOT from here https://oss.sonatype.org/content/repositories/snapshots/

It looks like some optimization I did for Expression creation and comparison didn't work in the case when serialized expressions are used.

@jotomo

This comment has been minimized.

Show comment
Hide comment
@jotomo

jotomo Aug 23, 2013

Thanks, I'll give it a try on Monday.

jotomo commented Aug 23, 2013

Thanks, I'll give it a try on Monday.

@jotomo

This comment has been minimized.

Show comment
Hide comment
@jotomo

jotomo Aug 26, 2013

Your commit fixed the bug. I wrote a bunch of tests to exercise a bit more of QueryDSL beyond the original select and it's all working smoothly. Thanks a lot Timo! :-)

jotomo commented Aug 26, 2013

Your commit fixed the bug. I wrote a bunch of tests to exercise a bit more of QueryDSL beyond the original select and it's all working smoothly. Thanks a lot Timo! :-)

@jotomo jotomo closed this Aug 26, 2013

@timowest

This comment has been minimized.

Show comment
Hide comment
@timowest

timowest Aug 26, 2013

Member

Good. I'll close it when it's released.

Member

timowest commented Aug 26, 2013

Good. I'll close it when it's released.

@timowest timowest reopened this Aug 26, 2013

@timowest

This comment has been minimized.

Show comment
Hide comment
@timowest

timowest Aug 27, 2013

Member

Released in 3.2.3

Member

timowest commented Aug 27, 2013

Released in 3.2.3

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment