I'm using spring-data-mongodb 1.8.0; MongoDB 3.0.6; mongo-java-driver 3.1.0;spring-framework.version 4.0.3.
What I want is to query a list of user with certain phone numbers.
example for user: { "_id" : ObjectId("5625e5c32e1ca013a03f0d1b"), "phone" : "12345535"}
In Mongo Shell db.user.find({phone: { $in: [ "12345535", "123535"]}}) works fine. But in Spring I failed. Java Class User(with getters/setters omitted):
#Document(collection = "user")
public class User {
#Id
String id;
String phone;
}
What I tried is:
Query q = new Query(Criteria.where("phone").in("12345535","123535"));
mongoTemplate.find(q, User.class);
It comes to error:
Exception in thread "main" java.lang.IllegalAccessError: tried to access class org.springframework.beans.PropertyMatches from class org.springframework.data.mapping.PropertyReferenceException
at org.springframework.data.mapping.PropertyReferenceException.detectPotentialMatches(PropertyReferenceException.java:134)
at org.springframework.data.mapping.PropertyReferenceException.<init>(PropertyReferenceException.java:59)
at org.springframework.data.mapping.PropertyPath.<init>(PropertyPath.java:75)
at org.springframework.data.mapping.PropertyPath.create(PropertyPath.java:327)
at org.springframework.data.mapping.PropertyPath.create(PropertyPath.java:307)
at org.springframework.data.mapping.PropertyPath.from(PropertyPath.java:270)
at org.springframework.data.mongodb.core.convert.QueryMapper$MetadataBackedField.getPath(QueryMapper.java:837)
at org.springframework.data.mongodb.core.convert.QueryMapper$MetadataBackedField.<init>(QueryMapper.java:729)
at org.springframework.data.mongodb.core.convert.QueryMapper$MetadataBackedField.with(QueryMapper.java:740)
at org.springframework.data.mongodb.core.convert.QueryMapper$MetadataBackedField.with(QueryMapper.java:686)
at org.springframework.data.mongodb.core.convert.QueryMapper.getMappedKeyword(QueryMapper.java:258)
at org.springframework.data.mongodb.core.convert.QueryMapper.getMappedObjectForField(QueryMapper.java:200)
at org.springframework.data.mongodb.core.convert.QueryMapper.getMappedObject(QueryMapper.java:123)
at org.springframework.data.mongodb.core.MongoTemplate.doFind(MongoTemplate.java:1700)
at org.springframework.data.mongodb.core.MongoTemplate.doFind(MongoTemplate.java:1690)
at org.springframework.data.mongodb.core.MongoTemplate.find(MongoTemplate.java:602)
at org.springframework.data.mongodb.core.MongoTemplate.find(MongoTemplate.java:593)
at com.example.TestMongo.main(TestMongo.java:30)
But with changing field phone to id, same code works fine.
Query q = new Query(Criteria.where("id").in("5625e5c32e1ca013a03f0d1b","f0d1e"));
mongoTemplate.find(q, User.class);
With debugging, I find that it even didn't go to the request phase, error occurred in the query-building phase. It seems $in cannot be processed by PropertyPath.create, while in the id case, it can.
How can I fix this? I am a newbie and searched a lot but got no luck.Can you please help me out. Every answer is appreciated. Thanks guys.
As indicated in the announcement blog and the release train wiki, Spring Data MongoDB 1.8 requires Spring 4.1, ideally 4.1.8 which includes an important security fix.
The issue have appeared on me while using Spring 4.2.3.RELEASE and Spring MongoDB 1.6.1
Switching to Spring mongoDB 1.8.1 solves the issue.
(Meant as a comment to #OliverGierke's answer, but couldn't do it, due to low reputation level.)
Related
After upgrading to the latest Spring Boot Version, several tests in classes that have the annotation "#DataJpaTest" were no longer working. Many things broke, but what was specifically weird was that "findBy" methods do not seem to query data correctly (when I run integration tests or do manual tests, they work fine). Here is a basic test I ran:
#Test
fun `When findByActivationTokenId then return Account`() {
val firstName = "John"
val lastName = "Doe"
val phone = "1234"
val email = "test#gmail.com"
val providerId = "google"
val providerUserId = "123"
val activationToken = UUID.randomUUID()
val account = Account(
firstName = firstName,
lastName = lastName,
email = email,
phoneNumber = phone,
providerId = providerId,
providerUserId = providerUserId,
title = "Herr",
activationTokenId = activationToken
)
entityManager.persist(account)
entityManager.flush()
val allAccounts = accountRepository.findAll()
val found = accountRepository.findByActivationTokenId(activationToken)
found.get() shouldNotBe null
found.get().providerId shouldBe providerId
found.get().providerUserId shouldBe providerUserId
}
I called "findAll()" so I can look at the result with the debugger. What I noticed was that the repository does in fact return the account exactly the way I persisted it, with the right activation token ID. The "findByActivationTokenId", however, returns an empty optional. Is this a bug or an oversight on my part? I looked into the deprecation information and found nothing specific to Spring Data JPA that could effect tests only.
The problem is related to the embedded h2 database. With the latest upgrade, a lot of features will no longer work with JPA. Here is the changelog:
http://www.h2database.com/html/migration-to-v2.html
This is a more specific comment on the implications for migration to Spring Boot 2.7 and using the new Version:
https://twitter.com/odrotbohm/status/1526594686932160515
There are various things that might go wrong here, and just as mpbeaujean I suspect the new version of H2 to be the culprit.
There are various things you can try. Which one is the right one for you depends on your specific reason to use H2.
Don't use H2. Often H2 is used in tests while something else is used in production. This is a crutch at best and I recommend to switch to Testcontainers and a docker image of the exact database version you have in production.
You could revert to H2 1.4. Just note that there is a CVE for it. If I remember correctly you can mitigate it when you make sure that the JDBC URL used is trusted. But you should research the CVE in order to decide if it is a problem for you.
If you have to use the current version of H2, or if not using it doesn't resolve the problem, you need to find out what is going on.
I'd try the answers given here first.
If it doesn't help, please post the class definition of your entity, the DDL for your table and the SQL including parameters that gets executed.
I have issue with Spring data. When I use #Query annotation with Pageable, for example:
#Query("SELECT * FROM myTable WHERE myTable.t_blob_name > NULL")
Slice<MyTable> findAllWithPageable(Pageable pageable);
I will have next exception (That application runs on Google cloud platform):
org.springframework.cloud.gcp.data.datastore.core.mapping.DatastoreDataException: Unable to convert class org.springframework.data.domain.PageRequest to Datastore supported type.
at org.springframework.cloud.gcp.data.datastore.core.convert.DatastoreNativeTypes.wrapValue (DatastoreNativeTypes.java:166)
at org.springframework.cloud.gcp.data.datastore.core.convert.TwoStepsConversions.convertOnWriteSingle (TwoStepsConversions.java:320)
at org.springframework.cloud.gcp.data.datastore.repository.query.GqlDatastoreQuery.bindArgsToGqlQuery (GqlDatastoreQuery.java:233)
at org.springframework.cloud.gcp.data.datastore.repository.query.GqlDatastoreQuery.execute (GqlDatastoreQuery.java:118)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke (RepositoryFactorySupport.java:605)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.lambda$invoke$3 (RepositoryFactorySupport.java:595)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke (RepositoryFactorySupport.java:595)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed (ReflectiveMethodInvocation.java:186)
at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke (DefaultMethodInvokingMethodInterceptor.java:59)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed (ReflectiveMethodInvocation.java:186)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke (ExposeInvocationInterceptor.java:93)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed (ReflectiveMethodInvocation.java:186)
at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke (SurroundingTransactionDetectorMethodInterceptor.java:61)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed (ReflectiveMethodInvocation.java:186)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke (JdkDynamicAopProxy.java:212)
It's a google cloud DataStore syntax and the main question - how to resolve that problem?
There is a list of supported classes that can be used within GQL. You can find it in reference point 158.5.2 and directly in code on GitHub if you prefer. Actually the Pageable class is not among them.
I noticed that you are not using this paramater in the query so I suggest to use Slice<MyTable> findAllWithPageable() Similar query you may find in here.
I hope it will help!
In Spring Boot 2.1.2, in the default log4j2.xml file, I noticed the following line:
<Property name="LOG_EXCEPTION_CONVERSION_WORD">%xwEx</Property>
I have been searching for the meaning of the %xwEx conversion pattern all day (yes, even the second page of Google), but I can't figure it out. And it is not listed in the table of patterns within the official documentation.
What does it mean?
Many thanks to Christoph for the answer on GitHub:
If I'm not mistaken this is a Spring-Boot specific converter plugin for log4j2. See ExtendedWhitespaceThrowablePatternConverter:
#Plugin(name = "ExtendedWhitespaceThrowablePatternConverter", category = PatternConverter.CATEGORY)
#ConverterKeys({ "xwEx", "xwThrowable", "xwException" })
public final class ExtendedWhitespaceThrowablePatternConverter
extends ThrowablePatternConverter {
// ....
}
As I'm not a team member don't take this for granted though.
Cheers,
Christoph
I'm trying to expose in Rest my repository written in Spring
#RepositoryRestResource(collectionResourceRel = "product", path = "product")
interface ProductRepository : MongoRepository<ProductBean, Long> {
#RestResource(path = "findByBizid")
fun findByBizid(#Param("bizid") bizid : String): List<ProductBean>
}
Compilation is ok, no warning.
If I understood well, the following url should return my custom query method
http://127.0.0.1:8080/product/search/findByBizid?bizid=AB
But I got an empty response and a spring exception is raised and displayed in the spring console of Intellijidea:
WARN 39290 --- [nio-8080-exec-1]
.m.m.a.ExceptionHandlerExceptionResolver : Resolved exception caused
by Handler execution:
org.springframework.data.rest.webmvc.ResourceNotFoundException:
Resource not found!
I spend a full night on it, I'm completly lost
I tried to simplify my code, copy paste some tutorial examples, nothing worked.
I figured out that 127.0.0.1:8080/product/search method is not working either. Even if I am removing my customs methods.
Any idea how to debug this?
Anthony
Update:
I forgot to tell that classical repository list is running well: 127.0.0.1:8080/product is retrieving all product in the db
We have implemented our repositories exactly as demonstrated in the Spring Data documentation. Everything was fine until we upgraded from STS 2.9 to STS 3.1. All attempts to get these errors to disappear have failed, and in some cases they don't even make sense! They don't match any properties in either the interface or the entities used!
Here is an example:
public interface CreditNotesRepository extends JpaRepository<CreditNotes, Long> {
CreditNotes findCurrentCreditNotes(Long shipmentDetailId);
}
The findCurrentCreditNotes is a named query in our entity. This code executes perfectly fine.
#NamedQueries({
#NamedQuery(name = "CreditNotes.getCount", query = "SELECT COUNT(f) FROM CreditNotes f"),
#NamedQuery(name = "CreditNotes.findCurrentCreditNotes", query =
"SELECT creditNotes FROM CreditNotes creditNotes"
+ " WHERE creditNotes.shipmentDetail.shipmentDetailId = ?1 "
+ " AND creditNotes.notesSeqNumber = (SELECT max(creditNotes2.notesSeqNumber) FROM CreditNotes creditNotes2"
+ " WHERE creditNotes.shipmentDetail.shipmentDetailId = creditNotes2.shipmentDetail.shipmentDetailId)")
})
And the error we get:
Invalid derived query! No property find found for type ca.cole.freight.model.CreditNotes
Although this is just a flag (doesn't affect compilation), it is annoying and confusing. Can anyone shed some light on this? And explain it to me like I'm 6 years old! ;)
At the post on the Spring Forum, Spring Team announced that
It is already fixed for STS 3.3.0
I didn't check this version yet. But I'm using 3.5.0.RELEASE and the problem comes back! My fix is to uncheck Invalid Derived Query
It's an IDE error explained in the following post:
http://forum.springsource.org/showthread.php?138585-Invalid-derived-query!-No-property-delete-found-for-type-java-lang-Object
In the meantime, you can turn off the validation in preferences/spring/project validators/Data validator uncheck invalid derived query and STS wont throw the marker anymore.
There is also workaround for this. Add #Query annotation on your method definition in Your repository without JPQL/SQL query defined.
Here is example :
#Query
List<OwnerModel> findByFirstNameAndAgeNotZero(#Param(value = "firstName") String firstName);
In this case named query OrderModel.findByFirstNameAndAgeNotZero will be used. Your Eclipse error Invalid derived query should also disappear without need of disabling validation as described by #Tuan Dang
Checked on Eclipse 4.5.1 with Spring plugin installed for #NamedQuery and #NamedNativeQuery.
I've just been going through this myself. Unfortunately, the implementation of Spring Data changed between 1.1 and 1.2. It no longer supports the <repository> XML declaration. You can set up a custom postfix, but by default, it expects a bean of class name <InterfaceName>Impl. If it can't find the custom repository implementation, you start getting errors like the one you're encountering. It's trying to create methods to query for objects based on names of methods in your interface.
An alternative is to back your Spring Data version down to 1.1 and specify a schemalocation of http://www.springframework.org/schema/data/jpa/spring-jpa-1.1.xsd in your XML.