How to insert Date object with the latest mongojack? - mongodb

so in my object, I have private Date date; when I insert I got this exception:
Caused by: com.fasterxml.jackson.databind.JsonMappingException: JsonGenerator of type org.mongojack.internal.object.document.DocumentObjectGenerator not supported: org.mongojack.internal.DateSerializer is designed for use only with org.mongojack.internal.object.BsonObjectGenerator or org.mongojack.internal.stream.DBEncoderBsonGenerator or com.fasterxml.jackson.databind.util.TokenBuffer (through reference chain: com.test.DocumentWrapper["date"])
I am trying to set up the mongo TTL by using that date field.

I have had the same issue recently: to store date as Date object into MongoDB via MongoJack.
First of all, I used MongoJack 2.10.0 version.
And it requires to create own Serializer and Deserializer.
public class Serializer extends JsonSerializer<DateTime> {
#Override
public void serialize(DateTime value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
gen.writeObject(new Date(value.getMillis()));
}
}
public class Deserializer extends JsonDeserializer<DateTime> {
private static final DateDeserializer DATE_DESERIALIZER = new DateDeserializer();
#Override
public DateTime deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
Date date = DATE_DESERIALIZER.deserialize(p, ctxt);
return date == null ? null : new DateTime(date);
}
}
.....
#JsonSerialize(using = Serializer.class)
#JsonDeserialize(using = Deserializer.class)
private DateTime testDate;
public DateTime getTestDate() {
return testDate;
}
public void setTestDate(DateTime testDate) {
this.testDate = testDate;
}
......
In my case, I converted Date into joda DateTime to keep consistency with my code but it's possible to change to another type (LocalDateTime, OffsetDateTime, etc.)

To solve this issue, please use the 2.10.0 version which has fixed this bug.

Related

Casting an unknown enum value to default enum in spring boot mongo repository actions

I have problem while casting an unknown enum to a default enum in spring boot while using mongo repository.
This is the enum.
public enum EventType implements Serializable
{
WORKDONE("WORKDONE"),
ODRCOM("ODRCOM"),
EXECUTED("EXECUTED"),
REBOOK("REBOOK"),
MANUAL("MANUAL"),
UNKNOWN("UNKNOWN");
private String value;
EventType(final String type) {
this.value = type;
}
#Override
public String toString() {
return value;
}
}
And here is my model class
#JsonInclude(JsonInclude.Include.NON_NULL)
public class Event {
//other properties
#JsonProperty("eventType")
private EventType eventType;
#JsonIgnore
private Map<String, Object> additionalProperties = new HashMap<String, Object>();
#JsonProperty("eventType")
public EventType getEventType() {
return eventType;
}
#JsonProperty("eventType")
public void setEventType(String eventType) {
this.eventType = Optional.ofNullable(EventType.valueOf(eventType)).orElse(EventType.UNKNOWN);
}
//other getters and setters
}
Here is the mongo repository
public interface EventRepository extends MongoRepository<Event, String> {
}
The document stored in the db is of the following stucture
{
...
"eventType" : "REBOOK1",
...
}
Please note that the REBOOK1 is not a valid enum. But the setter should be able to able to cast anything else to type UNKNOWN.
However it gives this exception everytime
No enum constant dk.nuuday.ossieventprocessor.app.model.EventType.REBOOK1
I have tried with adding a custom converter as a configuration but no luck
Any help is greatly appreciated

How to supply LocalDateTime to a jpa/hibernate query?

I'm building a query in my #RepositoryRestResource
where the query looks like this:
#Query("Select DISTINCT comp from InsuranceCompany comp " +
"LEFT JOIN comp.orders ord " +
"wHERE ord.invoiced = false " +
"and (:date is null or :date >= ord.completionTime)"
)
public Page<InsuranceCompany> method(LocalDateTime date, Pageable pageable);
But it throws the following excpetion
Failed to convert from type [java.lang.String] to type [java.time.LocalDateTime] for value '2020-02-14T15:50:24'
when I call the end point with:
GET /method?date=2020-02-14T15:50:24
Mark it with #DateTimeFormat to have Spring converted it correctly:
public Page<InsuranceCompany> method(#DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime date,
Pageable pageable);
Spring by default cannot convert REST parameters to LocalDateTime. You need to provide information on the format of the date, at a parameter level with the #DateTimeFormat annotation, or globally using the DateTimeFormatterRegistrar.
This article explains the two alternatives: https://www.baeldung.com/spring-date-parameters
Option 1: Setting the date/time format globally for all Spring Boot App REST Endpoints
You can configure spring globally to use a certain date / date-time format for your REST endpoints. Suggesting that you use the default Jackson for handling JSON mapping, you can create a configuration class as follows where you set the formats:
#Configuration
public class DateTimeSerializationConfiguration implements Jackson2ObjectMapperBuilderCustomizer {
private static final DateTimeFormatter DATE_FORMATTER = ISO_LOCAL_DATE;
private static final DateTimeFormatter DATE_TIME_FORMATTER = ISO_DATE_TIME;
private static final DateTimeFormatter TIME_FORMATTER = ofPattern("HH:mm");
#Bean
public Formatter<LocalDate> localDateFormatter() {
return new Formatter<LocalDate>() {
#Override
public LocalDate parse(String text, Locale locale) {
return LocalDate.parse(text, DATE_FORMATTER);
}
#Override
public String print(LocalDate object, Locale locale) {
return DATE_FORMATTER.format(object);
}
};
}
#Bean
public Formatter<LocalDateTime> localDateTimeFormatter() {
return new Formatter<LocalDateTime>() {
#Override
public LocalDateTime parse(String text, Locale locale) {
return LocalDateTime.parse(text, DATE_TIME_FORMATTER);
}
#Override
public String print(LocalDateTime object, Locale locale) {
return DATE_TIME_FORMATTER.format(object);
}
};
}
#Bean
public Formatter<LocalTime> localTimeFormatter() {
return new Formatter<LocalTime>() {
#Override
public LocalTime parse(String text, Locale locale) {
return LocalTime.parse(text, TIME_FORMATTER);
}
#Override
public String print(LocalTime object, Locale locale) {
return TIME_FORMATTER.format(object);
}
};
}
#Override
public void customize(Jackson2ObjectMapperBuilder jacksonObjectMapperBuilder) {
jacksonObjectMapperBuilder.serializers(
new LocalDateSerializer(DATE_FORMATTER),
new LocalDateTimeSerializer(DATE_TIME_FORMATTER),
new LocalTimeSerializer(TIME_FORMATTER));
jacksonObjectMapperBuilder.deserializers(
new LocalDateDeserializer(DATE_FORMATTER),
new LocalDateTimeDeserializer(DATE_TIME_FORMATTER),
new LocalTimeDeserializer(TIME_FORMATTER));
}
}
Then, you can create controller methods like this:
#RestController
public class BookingController {
private final YourService yourService;
#Autowired
public BookingController(YourService yourService) {
this.yourService = yourService;
}
#GetMapping("/your/api/endpoint")
public YourObject yourControllerMethod(#RequestParam LocalDate date, Pageable pageable) {
return yourService.yourServiceMethod(date, pageable);
}
// Or: with LocalDateTime
#GetMapping("/your/api/endpoint")
public YourObject yourControllerMethod(#RequestParam LocalDateTime dateTime, Pageable pageable) {
return yourService.yourServiceMethod(dateTime, pageable);
}
}
Option 2: Setting the date/time format for each REST Endpoint individually
If you prefer to set the format for each endpoint individually, you have to annotate the request parameter with #DateTimeFormat and specify the expected format. The example below shows different examples on how to accomplish this:
#RestController
public class BookingController {
private final YourService yourService;
#Autowired
public BookingController(YourService yourService) {
this.yourService = yourService;
}
#GetMapping("/your/api/endpoint")
public YourObject yourControllerMethod(#RequestParam #DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate date, Pageable pageable) {
return yourService.yourServiceMethod(date, pageable);
}
// Or: with LocalDateTime
#GetMapping("/your/api/endpoint")
public YourObject yourControllerMethod(#RequestParam #DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime dateTime, Pageable pageable) {
return yourService.yourServiceMethod(dateTime, pageable);
}
// Or: with your custom pattern
#GetMapping("/your/api/endpoint")
public YourObject yourControllerMethod(#RequestParam #DateTimeFormat(pattern = "dd.MM.yyyy") LocalDate date, Pageable pageable) {
return yourService.yourServiceMethod(date, pageable);
}
}

How to pass String[] as varchar[] through Querydsl to PostgreSQL?

Trying to solve Postgresql Array Functions with QueryDSL more cleanly, I've got this far.
// obj.foo is an ArrayPath<String[], String>
bindings.bind(obj.foo).first((path, value) ->
Expressions.booleanTemplate("arraycontains({0}, {1}) = true", path, value));
this ends up as correct-looking SQL
where arraycontains(obj0_1_.foo, ?)=true
but it seems the String[] variable is not passed correctly
org.postgresql.util.PSQLException: ERROR: function arraycontains(character varying[], bytea) does not exist
How can I either (if possible)
get the String[] value to bind as a varchar[]?
express the necessary cast in the booleanTemplate?
Instead of passing the String[] directly, wrap it in a TypedParameterValue.
The hibernate-types library does not yet support varchar[], but you can use it to build something that does:
public class VarcharArrayType extends AbstractHibernateType<String[]> {
public static VarcharArrayType INSTANCE = new VarcharArrayType();
public VarcharArrayType() {
super(ArraySqlTypeDescriptor.INSTANCE, new TypeDescriptor());
}
public String getName() {
return "varchar-array";
}
public static class TypeDescriptor extends StringArrayTypeDescriptor {
#Override
protected String getSqlArrayType() {
return "varchar";
}
}
}

BLOB as parameter in procedure call in mybatis

This is the call in the ProductServices.xml
<update id="resetPassword" parameterType="batchReport">
{ call user_account_mng.enc_reset_password(
#{user_Id,jdbcType=VARCHAR,mode=IN},
#{encrypted_password,jdbcType=VARCHAR,mode=IN},
#{usr_id, dbcType=VARCHAR,mode=IN},
#{salt,jdbcType=VARCHAR,mode=IN},
#{ret_code,jdbcType=CHAR,mode=OUT},
#{pgp_encrypted_password,jdbcType=BLOB,mode=IN}
)}
Now BatchReport is a POJO:
(i have declared an alias for it as batchReport)
public class BatchReport
{
private String user_Id;
private String encrypted_password;
private String usr_id;
private String salt;
private String ret_code;
private byte[] pgp_encrypted_password;
public String getUser_Id() {
return user_Id;
}
public void setUser_Id(String user_Id) {
this.user_Id = user_Id;
}
public String getEncrypted_password() {
return encrypted_password;
}
public void setEncrypted_password(String encrypted_password) {
this.encrypted_password = encrypted_password;
}
public String getUsr_id() {
return usr_id;
}
public void setUsr_id(String usr_id) {
this.usr_id = usr_id;
}
public String getSalt() {
return salt;
}
public void setSalt(String salt) {
this.salt = salt;
}
public String getRet_code() {
return ret_code;
}
public void setRet_code(String ret_code) {
this.ret_code = ret_code;
}
public byte[] getPgp_encrypted_password() {
return pgp_encrypted_password;
}
public void setPgp_encrypted_password(byte[] pgp_encrypted_password) {
this.pgp_encrypted_password = pgp_encrypted_password;
}
}
My main class is like this :
<BatchReport batchReport = new BatchReport();
byte[] byteArray =new byte[]{1,2,3};
batchReport.setUser_Id("CHI");
batchReport.setEncrypted_password("97D6B45");
batchReport.setSalt("71L");
batchReport.setPgp_encrypted_password(byteArray);
String returnCode = productServiceObj.resetPassword(batchReport);
i am getting following error:
Error setting null parameter. Most JDBC drivers require that the JdbcType must be specified for all nullable parameters. Cause: java.sql.SQLException: Invalid column type
The error may involve com.example.services.ProductServices.resetPassword-Inline
ProductServices is a class in which the method resetPassword is declared.
Please help me with this BLOB issue.
What should be the jdbcType in the called procedure.
what value should be passed in this pgp_encrypted_password.
Okay I found the solution to the problem now the jdbcType in the query in .xml file remains the same i.e BLOB.
Next the type which gets set for passing in the values is byte[].
So everything remains same as i have covered up .
Error actually existed as the in .xml file returns an integer indicating the number of rows changed in query and I have given the function return type as String so here goes the solution for the problem it should be of type Object.

Date conversation error during jaxb marshall on a JPA object using eclipselink

I stuck on this Date conversation error for quite some time ...
I am using eclipselinks, openJPA under TomcatEE environment, and trying to use jaxb doing marshalling. I met a problem for marshall one JPA object, which contains Date, TimeStamp elements.
The exception message is ---
javax.xml.bind.MarshalException
- with linked exception:
[Exception [EclipseLink-3002] (Eclipse Persistence Services - 2.3.2.v20111125-r10461): org.eclipse.persistence.exceptions.ConversionException
Exception Description: The object [3/19/12 12:00 AM], of class [class org.apache.openjpa.util.java$util$Date$proxy], from mapping [org.eclipse.persistence.oxm.mappings.XMLDirectMapping[createTs-->createTs/text()]] with descriptor [XMLDescriptor(xxx.xxxx.xxx.xxxx.entities.ApplicationEntity --> [])], could not be converted to [class java.util.Date].]
The strange thing is jaxb converting works OK for some customers, but not some other customer. I tried to put #XmlElement(type=Date.class) for this field crtTs, It doesn't work.
Thanks for your help in advance.
LL
I have been able to reproduce the issue you are seeing. You can use the following bug to track our progress on this issue:
http://bugs.eclipse.org/383639
WORK AROUND
DateAdapter
You could use an XmlAdapter to convert the problematic date into a proper java.util.Date.
package forum11145711;
import java.util.Date;
import javax.xml.bind.annotation.adapters.XmlAdapter;
public class DateAdapter extends XmlAdapter<Date, Date>{
#Override
public Date unmarshal(Date date) throws Exception {
return date;
}
#Override
public Date marshal(Date date) throws Exception {
if(null == date) {
return date;
}
return new Date(date.getTime());
}
}
Root
The #XmlJavaTypeAdapter annotation is used to leverage the XmlAdapter:
package forum11145711;
import java.util.Date;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
#XmlRootElement
public class Root {
private Date date;
#XmlJavaTypeAdapter(DateAdapter.class)
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
}
MyDate
Below is the subclass of java.util.Date I'm using in this example.
package forum11145711;
import java.util.Date;
public class MyDate extends Date {
}
Demo
Below is some demo code you can use to prove that everything works:
package forum11145711;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Root.class);
Root root = new Root();
root.setDate(new MyDate());
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(root, System.out);
}
}
Output
<?xml version="1.0" encoding="UTF-8"?>
<root>
<date>2012-06-27T10:39:49.081</date>
</root>