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
Interface-based projection mixes data order [DATAJPA-1247] #1582
Comments
Oliver Drotbohm commented That's a sort of known problem but you can usually work around this by using explicit aliases in the query definition. Derived queries actually use those so that the problem shouldn't occur for those. DATACMNS-1206 is approaching that problem and making sure we read the property definitions in projection interfaces in stable order. Just to make sure I completely understand your particular scenario, would you mind giving a concrete example (including samples of the projection definition and query method declaration) of the situation you're running into this problem? |
Antti Huokko commented I would actually prefer using aliases with projections but I did not find any code (in Spring) that would actually use then when making the projection for native queries. This made be believe that aliases can't be used with native query projections. Here are some example code how I tested this. In example there are 2 queries: one that uses aliases and one that does not. However the result of the projection is same for both queries. Sorry for the finnish language in database query :) import java.time.LocalDateTime;
public interface TestProjection {
long getId();
int getVersion();
LocalDateTime getTime();
String getState();
} The query methods that I have in the JpaRepository @Query(value="SELECT hak.kihak_id, hak.versio, hak.luonti_pvm, hak.hakemustila FROM kiireellinen_hakemus hak WHERE hak.haetun_aikataulun_lahtoaika > :time", nativeQuery=true)
List<TestProjection> getTestProjection1(LocalDateTime time);
@Query(value="SELECT hak.kihak_id AS id, hak.versio AS version, hak.luonti_pvm AS time, hak.hakemustila AS state FROM kiireellinen_hakemus hak WHERE hak.haetun_aikataulun_lahtoaika > :time", nativeQuery=true)
List<TestProjection> getTestProjection2(LocalDateTime time); Code in the service that uses the test repository to make the queries List<TestProjection> res1 = testRepository.getTestProjection1(LocalDateTime.of(2018, 1, 1, 12, 0));
System.out.println(res1.get(0)); // {id=541626, state=3, time=2017-12-28 09:25:04.0, version=Hyväksytty} => version should be int not String
List<TestProjection> res2 = testRepository.getTestProjection2(LocalDateTime.of(2018, 1, 1, 12, 0));
System.out.println(res2.get(0)); // {id=541626, state=3, time=2017-12-28 09:25:04.0, version=Hyväksytty} => version should be int not String Excellent news that the order problem will be fixed in the future version. |
Oliver Drotbohm commented I was thinking of using explicit aliases in the query, yes. So you're saying that the second query declaration really has the result mixed up, too? You shouldn't actually see a One thing I am curious about is what Hibernate version you're using? in DATAJPA-1209, we identified an issue that caused us to not be able to use |
Antti Huokko commented Also the query with aliases (getTestProjection2) produces the projection with incorrect property order. Also when I debug the case I see that the execution of code goes to the ProjectingConverter.toMap(...) method that is the source of the incorrect order. To me it seems that using or not using the aliases don't have any effect. The version of Hibernate that we are using is 5.2.10 |
Oliver Drotbohm commented Okay, I just ran the test case we have for that scenario on a Hibernate 5.2, and even without explicitly defined aliases I see the following things:
Would you mind following those corner stones and see where things start to diverge? |
Antti Huokko commented For me the code starts to diverge in first step. For me the NativeJpaQuery.createJpaQuery(…) sees a resultType of null |
Oliver Drotbohm commented Ha! The fix in Hibernate is in 5.2.11 and newer (see our explicit check for that). Would you mind trying that? |
Antti Huokko commented I just found the same check. I updated Hibernate to version 5.2.12 and now thing start to work. The native query with aliases now return projection with correct order. Thank you for your help solving this! |
Jens Schauder commented Batch closing resolved issue without a fix version and a resolution indicating that there is nothing to release (Won't fix, Invalid ...) |
Antti Huokko opened DATAJPA-1247 and commented
When using Interface-based projection with native query Spring generates the data proxy with data bind to incorrect getters. The problem is caused by the fact that the code that binds data to the proxy properties relies on the order. The logic that combines property names and data is in ResultProcessor inner class called ProjectingConverter. There in the toMap(...) method the property names and values are combined to a Map. The actual source of the problem is where the property names are obtained. The property names are obtained using BeanUtils.getPropertyDescriptors(Class). The problem here is that Java does not guarantee any order for the property descriptors that it returns. This means that basically each time application is started we might get different property order. As a result of this the properties of the projection will experience some very odd random behavior as data is bind to incorrect fields.
To me this sounds like a major bug that will cause unpredictable and hard-to-reproduce problems. For instance if we have a projection interface consisting of 3 int getters this bug will cause data field to switch place at random without any runtime exceptions. This is a source of some very hard to find and hard to reproduce bugs in application logic.
Affects: 1.11.9 (Ingalls SR9)
Issue Links:
DATAJPA-1209 Compatibility with Hibernate < 5.2.11 broken for projections on native queries
DATACMNS-1206 Introduce abstraction to detect declared methods in declaration order
The text was updated successfully, but these errors were encountered: