I have a SpringBoot JPA Repository that finds a bunch of "things" in a MongoDB instance that has a field called "lastModified" which is an ISODate() as per the below.
{ "name": "a", "lastModified", "ISODate(2018-04-19T19:10:39.356574)" }
When I use a repository function like:
public List<Thing> findByName(String name);
I get a
org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.String] to type [java.util.Date] for value 'ISODate(2018-04-18T18:38:42.635027)'; nested exception is java.lang.IllegalArgumentException
I have tried
Creating separate setters and constructors that take each java.util.Date and
String and do a converstion with a
SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSSSS")
Using
#DateTimeFormat(pattern="yyyy-MM-dd'T'HH:mm:ss.SSSSSS") on the
lastModified parameter on the Entity
Am I missing something about how Mongo does this conversion? I would expect it turns that ISODate into a simple string and passes it into the setLastModified(String name) function but I guess that's not the case?
Turns out it was just because the date was inserted as a string of "ISODate(2018-04-19T19:10:39.356574)" instead as a Date which would be like ISODate("2018-04-17T19:43:00Z")
Once I went and found and fixed the source of this data, it started working properly.
Related
I have a java class as follows
#Data
#Document(collection="sample_collection")
public class sampleClass {
private Instant createTime;
private Object payLoad;
// some more fields
}
The payload object can be null or object of different classes, and can contain a field of type byteBuffer.
Now, while trying to save this to Mongo as a document, I get no issues, but which retrieving the document, I get the instantiationException( whenever the payload object is populated and has the byteBuffer field )
Below are the exception details:
org.springframework.data.mapping.model.MappingInstantiationException: Failed to instantiate java.nio.HeapByteBuffer using constructor NO_CONSTRUCTOR with arguments
at org.springframework.data.convert.ReflectionEntityInstantiator.createInstance
at org.springframework.data.convert.ClassGeneratingEntityInstantiator.createInstance
at org.springframework.data.mongodb.core.convert.MappingMongoConverter.read
I'm unable to find a way to define a constructor for the HeapByteBuffer field.
Any leads would be appreciated.
From my point of view you should use more concrete class as field in your entity
OR
you can try to use Converters as workaround of this issue:
Setup custom converters in Spring Data Mongo
I'm trying to implement optimistic locking for documents in an existing MongoDB database. Currently there is no version field and I would like to avoid adding it because we'll have to stop the application.
But there is a lastModified date field and it seems that I can make use of it like this:
#LastModifiedDate
#Version
private Date lastModified;
But when I marked this field as #Version and tried to save an item, I got the following exception:
No converter found capable of converting from type [java.lang.Date] to type [java.lang.Number]
So, I also added Date to Number and Long to Date converters to my configuration:
#Configuration
public class MongoConfig extends AbstractMongoConfiguration {
...
#Override
public CustomConversions customConversions() {
return new CustomConversions(CustomConversions.StoreConversions.NONE,
Arrays.asList(
new DateToNumberConverter(),
new LongToDateConverter()
));
}
}
This works like a charm for existing documents. But when I try to add a new document, I get:
No converter found capable of converting from type [java.lang.Integer] to type [java.util.Date]
If I then add an Integer to Date converter, then the new document is saved in the DB, but all the dates are now NumberLong instead of ISODate, i.e. was "lastModified" : ISODate("2018-10-02T07:30:12.005Z") and now "lastModified" : NumberLong("1538465479364"). This breaks the consistency between existing documents and new ones.
So the questions are:
Is there any possibility to use java.util.Date with #Version so that all dates are stored as ISODate in MongoDB?
Could anyone point to documentation on optimistic locking in Spring Data for MongoDB apart from this: https://docs.spring.io/spring-data/mongodb/docs/current/reference/html/#mongo-template.optimistic-locking ?
Seems like currently there is no possibility to use Date as a version field because it is cast to Number inside MongoTemplate.
I solved the issue by using my custom MongoTemplate that extends the Spring Data MongoTemplate and overrides required methods. Unfortunately I had to copy-paste a lot of code because the overriden logic is in private methods.
I have entity Composition containing fields Date publicationDate and Boolean archival. I'm trying to get list of Compositions with publicationDate before date passed as argument and having archival flag set to false. After going through some of 'query creation from method names' tutorials and docs i came up with methods
List<Composition> findByPublicationDateBeforeDateAndArchivalFalse(Date date);
or
List<Composition> findByPublicationDateBeforeDateAndArchivalFalse(#Param("date")Date date);
but none of this works. Both gives UnsatisfiedDependencyException with
nested exception is org.springframework.data.mapping.PropertyReferenceException: No property beforeDate found for type Date! Traversed path: Composition.publicationDate.
Intellij also underlines BeforeDate as it cannot resolve property beforeDate. What is the proper way of using those keywords with parameters so the parameters could be distinguished from fields by Spring?
Refactor your method to following:
List<Composition> findByPublicationDateBeforeAndArchivalFalse(Date date);
Before keyword will compare publicationDate with date you pass as an argument, so there is no need to say BeforeDate. Just like an example in Spring Data documentation:
Before -> findByStartDateBefore produces following SQL part … where x.startDate < ?1
I'm trying to write a Spring MVC GET controller that takes a Java 8 Instant as request parameter:
#GetMapping
#JsonView(OrderListing.class)
#Validated
public WebSeekPaginatedResultsDto<OrderListingDto> findAll(#Valid OrderSearchCommand orderSearchCommand) {
// Some code
}
with:
public class OrderSearchCommand {
private Instant dateCreatedStart;
private Instant dateCreatedEnd;
// Some other fields
}
I'm triggering a GET request from some React/Javascript code with something like that:
http://localhost:8080/mms/front/orders?dateCreatedStart=2017-05-31T22%3A00%3A00.000Z
Spring does not seem to like it and throws an error. Here is the error message:
Failed to convert property value of type 'java.lang.String' to required type 'java.time.Instant' for property 'dateCreatedStart';
nested exception is java.lang.IllegalStateException:
Cannot convert value of type 'java.lang.String' to required type 'java.time.Instant' for property 'dateCreatedStart': no matching editors or conversion strategy found
Any idea why I'm getting this?
Thank you
Error message is self-explanatory:
there is no registered String to Instant converter.
When Controller receives request, all parameters are Strings. Spring/Jackson has list of predefined converter for most of basic types:
- String > Integer
- String > Boolean
But there is no default String > Instant converter.
You need to create and register one. Or you can change input type to something that Spring can handle with #DateTimeFormat annotation:
How to accept Date params in a GET request to Spring MVC Controller?
I suspect that the #DateTimeFormat will not work for Instant fields.
Specifically,
Instant is not listed as one of the types for which it works in the Spring reference doc.
Check out Spring Reference Section 9.5 for details about Spring custom type conversion.
Create a Converter<String, Instant> converter.
Section 9.5.5 covers custom type converter registration.
Maybe this can help you? serialize/deserialize java 8 java.time with Jackson JSON mapper I see that this Jackson include Instant class.
Suppose I have the class:
#Entity
public class Bean {
#Id
private String beanId;
//other fields & setters and getters
}
And the corresponding Spring Data JPA repository, where I want to have in a List<String> all the beanIds.
#RepositoryDefinition(domainClass = Bean.class, idClass = String.class)
public interface BeanRepository {
#Query("select b.beanId from Bean b")
List<String> findAllBeanId();
}
As written above, everything works as expected; but this is a simple operation and I do not want to write a query explicitly. What should the name of the method be such that Spring Data can parse it and obtain the above mentioned query (or the same functionality). I have searched in both the reference documentation as two books I have on Spring Data. The above name (findAllBeanId) and others that I have tried (findBeanId, findBeanBeanId etc.) throw the following exception as root cause:
org.springframework.data.mapping.PropertyReferenceException: No property find found for type Trade
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:353)
at org.springframework.data.mapping.PropertyPath.create(PropertyPath.java:353)
at org.springframework.data.mapping.PropertyPath.create(PropertyPath.java:307)
at org.springframework.data.mapping.PropertyPath.from(PropertyPath.java:271)
at org.springframework.data.mapping.PropertyPath.from(PropertyPath.java:245)
at org.springframework.data.repository.query.parser.Part.<init>(Part.java:72)
at org.springframework.data.repository.query.parser.PartTree$OrPart.<init>(PartTree.java:180)
at org.springframework.data.repository.query.parser.PartTree$Predicate.buildTree(PartTree.java:260)
at org.springframework.data.repository.query.parser.PartTree$Predicate.<init>(PartTree.java:240)
at org.springframework.data.repository.query.parser.PartTree.<init>(PartTree.java:68)
at org.springframework.data.jpa.repository.query.PartTreeJpaQuery.<init>(PartTreeJpaQuery.java:57)
at org.springframework.data.jpa.repository.query.JpaQueryLookupStrategy$CreateQueryLookupStrategy.resolveQuery(JpaQueryLookupStrategy.java:90)
at org.springframework.data.jpa.repository.query.JpaQueryLookupStrategy$CreateIfNotFoundQueryLookupStrategy.resolveQuery(JpaQueryLookupStrategy.java:162)
at org.springframework.data.jpa.repository.query.JpaQueryLookupStrategy$AbstractQueryLookupStrategy.resolveQuery(JpaQueryLookupStrategy.java:68)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.<init>(RepositoryFactorySupport.java:279)
at org.springframework.data.repository.core.support.RepositoryFactorySupport.getRepository(RepositoryFactorySupport.java:147)
at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.getObject(RepositoryFactoryBeanSupport.java:153)
at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.getObject(RepositoryFactoryBeanSupport.java:43)
at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.doGetObjectFromFactoryBean(FactoryBeanRegistrySupport.java:142)
... 22 more
In the Spring docs: http://static.springsource.org/spring-data/jpa/docs/1.3.0.RELEASE/reference/html/jpa.repositories.html there is nothing about getting only particular column/property from entity by query generated from method name. So I think that currently it is not possible.
The code you showed works/should work as expected. It's simply not causing the exception you see :).
The exception is referring to a Trade, which seems to indicate that you have a repository for Trade somewhere which seems to refer to a missing property. The code you've shown is definitely not the one causing the exception. This can effectively not be the case as you're defining the query manually so that the query derivation mechanism doesn't even kick in for the repo you've shown.
I've pushed a test case for you to see this in action.