Jersey Marshall Map<Date,List> - date

I start understanding how jersey works with JAXB. But today i faced a particular case where i want to marshall a Map of (Date,List) entries:
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class MyClass{
#XmlJavaTypeAdapter(MapAdapter.class)
private Map<Date,List<MyObject>> = new TreeMap<Date,List<MyObject>>(new DateCompareDesc());
}
The goal here is to marshall a Map whose entry is a Date with its corresponding list of MyObject. the map is sorted in desc order.
For this i implemented an Adapter for Map (MapAdapter, following #Blaise Doughan's tutorial, http://blog.bdoughan.com/2010/07/xmladapter-jaxbs-secret-weapon.html). The problem is on the Date key. I have an Error : Unable to marshall java.util.Date. So i tried this new Date Adapter :
public class DateAdapter extends XmlAdapter<String, Date> {
#Override
public Date unmarshal(String v) throws Exception {
//not implemented
}
#Override
public String marshal(Date v) throws Exception {
return v.toString();
}
}
Where can i add #XmlJavaTypeAdapter(DateAdapter.class) so that Jersey could marhsall Date as key to my TreeMap?
Thanks.

JAXB supports the marshalling/unmarshalling of java.util.Date to the standard XML schema types: date, time, dateTime. You can control the type used with the #XmlSchemaType annotation.
http://blog.bdoughan.com/2011/01/jaxb-and-datetime-properties.html
If your date information is not represented as one of the standard XML schema types, you can use an XmlAdapter similar to the one I used the following answer to a similar question:
jaxb unmarshal timestamp
If you need to use the XmlAdapter approach, the #XmlJavaTypeAdapter annotation would be placed on the Date field of the adapted object representing the entry in the Map. Below is what this might look like based on my blog: http://blog.bdoughan.com/2010/07/xmladapter-jaxbs-secret-weapon.html.
import javax.xml.bind.annotation.XmlValue;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
public class MyMapEntryType {
#XmlAttribute
#XmlJavaTypeAdapter(DateAdapter.class)
public Date key;
public List<MyObject> value;
}

Related

JPA Projection spring boot; repository mapping entity instant to do date

I have an entity that has a date modelled as an Instant
I have an DO object that has a date modelled as a Date
when i do the conversion myself in the constructor of the DO it works:
public class DO {
private Date someTimePoint;
public DO(Instant CreatedAt) {
this.someTimePoint = Date.from(CreatedAt);
}
}
and my repo works call:
List<DO> findBySomeField(UUID someField);
Give result.
However: The DO is generated and I do not have access to it, so the constructor is actually:
public DO(Date CreatedAt) {
So the question is:
Is there a way to have the conversion from Instant to Date done on the fly by Spring using the Projection methodology?
Reading https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#projections
doesn't give me any clues...

Jersey 2 with Jackson serialisation issue

Tools :
Weblogic 12c
Jersey 2.21.1
Jackson 2
public class Profile implements Serializable
{
private List<Status> orderStatus;
public void setOrderStatus(List<Status> orderStatus)
{
this.orderStatus = orderStatus;
}
public void getOrderStatus()
{
return orderStatus;
}
I have a simple POJO class as above.
I am facing below issue while using Jersey 2 with Jackson.
1)When Profile class is serialised , the JSON gets created as : {"OrderStatus":[{}]}
2)So the key generated is OrderStatus and not orderStatus
3)When this JSON gets de-serialised , it throws error -
Caused by: org.codehaus.jackson.map.exc.UnrecognizedPropertyException: Unrecognized field "OrderStatus" since it cannot
find field with OrderStatus but has field as orderStatus
I have tried adding :
#JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY,getterVisibility = JsonAutoDetect.Visibility.NONE, setterVisibility = JsonAutoDetect.Visibility.NONE)
hoping that serialisation will only use fields as a key (and will not use property) and JSON will be generated as {"orderStatus":[{}]} .
But it is not working and same error is thrown.
Is there any way we can serialise POJO with key as fields and not properties.
Can anybody please help here ?
If you want to make sure orderStatus is the name use specific JsonProperty :
#JsonProperty("orderStatus")
public void getOrderStatus()
#JsonProperty (also indicates that property is to be included) is used to indicate external property name

java.time.LocalDate not supported in native queries by latest Spring Data/Hibernate?

Problem: Native queries with Spring Data returning dates return java.sql.Date not java.time.LocalDate, despite the setup.
Context: A new project with Spring Boot 2.0.0.M5 (the latest), Hibernate 5.2.11, Hibernate-Java8 5.2.12 (which gives support for JSR310 classes as long as it's on the classpath).
Anonymized example below (the app is not really about birthdays):
public interface BirthdayRepository<T, ID extends Serializable> extends Repository<T, ID> {
#Query(value = "select day from birthdays", nativeQuery = true)
Iterable<java.sql.Date> getBirthdays(); //the return type should ideally be java.time.LocalDate
}
In the database (SQL Server), the day field is DATE and values are like 2017-10-24.
The problem is that at runtime, the Spring Data repository (whose implementation I cannot control, or is there a way?) returns java.sql.Date not java.time.LocalDate (Clarification: the return type appears to be decided by Spring Data and remains java.sql.Date even if I change the return type to be java.time.LocalDate, which is how I started to).
Isn't there a way to get LocalDate directly? I can convert it later, but (1) that's inefficient and (2) the repository methods have to return the old date/time classes, which is something I'd like to avoid. I read the Spring Data documentation, but there's nothing about this.
EDIT: for anyone having the same question, below is the solution, the converter suggested by Jens.
public class LocalDateTypeConverter {
#Converter(autoApply = true)
public static class LocalDateConverter implements AttributeConverter<LocalDate, Date> {
#Nullable
#Override
public Date convertToDatabaseColumn(LocalDate date) {
return date == null ? null : new Date(LocalDateToDateConverter.INSTANCE.convert(date).getTime());
}
#Nullable
#Override
public LocalDate convertToEntityAttribute(Date date) {
return date == null ? null : DateToLocalDateConverter.INSTANCE.convert(date);
}
}
It looks like you found a gap in the converters. Spring Data converts out of the box between java.util.Date and java.time.LocalDate but not between java.time.LocalDate and java.sql.Date and other date and time-related types in the java.sql package.
You can create your own converter to do that. You can use Jsr310JpaConverters as a template.
Also, you might want to create a feature request and if you build a converter for your use, you might even submit a pull request.
I know this is an older question, but my solution to this problem does not require a custom converter.
public interface BirthdayRepository<T, ID extends Serializable> extends Repository<T, ID> {
#Query(value = "select cast(day as date) from birthdays", nativeQuery = true)
Iterable<java.time.LocalDate> getBirthdays();
}
The CAST tells JPQL to use available java date\time types rather than java.sql.Date

how to pass namedQuery parameters in Apache Camel JPA by header?

I have this camel route:
from("direct:getUser")
.pollEnrich("jpa://User?namedQuery=User.findById&consumeDelete=false");
This is my user Entity:
#Entity
#NamedQueries({
#NamedQuery(name="User.findAll", query="SELECT u FROM User u"),
#NamedQuery(name="User.findById", query="SELECT u FROM User u WHERE u.id = :id")
})
public class User{
#Id
private String id;
}
I have tried this route by setting the header:
from("direct:getUser")
.setHeader("id", simple("myid"))
.pollEnrich("jpa://User?namedQuery=User.findById&consumeDelete=false");
But it is not working
Is there any method to set jpa properties by the headers? The camel documentation quote this in parameters option but i don't found the examples
Options: parameters
This option is Registry based which requires the # notation. This
key/value mapping is used for building the query parameters. It is
expected to be of the generic type java.util.Map where
the keys are the named parameters of a given JPA query and the values
are their corresponding effective values you want to select for. Camel
2.19: it can be used for producer as well. When it's used for producer, Simple expression can be used as a parameter value. It
allows you to retrieve parameter values from the message body header
and etc.
I hope it's not too late to answer. In any case I had a similar issue in my project, the client does a HTTP GET with a parameter id, which is used by the JPA query and the result is finally marshalled back to the HTTP client. I'm running camel in a Spring application.
I finally figured out how to achieve it in a reasonably clean way.
This is the RouteBuilder where the route is defined:
#Override
public void configure() throws Exception {
Class dataClass = SomeClass.class;
JacksonDataFormat format = new JacksonDataFormat();
format.setUnmarshalType(dataClass);
String jpaString = String
.format("jpa://%1$s?resultClass=%1$s&namedQuery=q1" +
"&parameters={\"id\":${headers.id}}", dataClass.getName());
from("jetty://http://localhost:8080/test").toD(jpaString) // note the .toD
.marshal(format)
}
And this is the StringToMapTypeConverter class, otherwise camel cannot convert {"id": X} to a map
public class StringToMapTypeConverter implements TypeConverters {
private static final ObjectMapper mapper = new ObjectMapper();
private static JavaType mapType;
static {
mapType = mapper.getTypeFactory().constructMapType(Map.class,
String.class, Object.class);
}
#Converter
public Map<String, Object> toMap(String map) throws IOException {
return mapper.readValue(map, mapType);
}
}
Remember to add it to the context. In Spring is something like:
<bean id="myStringToMapTypeConverter" class="....StringToMapTypeConverter" />
Refs:
http://camel.apache.org/jpa.html
http://camel.apache.org/message-endpoint.html#MessageEndpoint-DynamicTo
http://camel.apache.org/type-converter.html#TypeConverter-Addtypeconverterclassesatruntime

Swagger Model Schema Response: alternate label for LocalDate in SpringFox

We are using Swagger 2.x and SpringFox 2.0 to document our REST service created with Spring MVC.
We have a REST response with a property List<LocalDate> dates.
In the Model Schema of the response, the label for dates is shown as 'LocalDate'. That is not intended: we would like to have 'date' or 'yyyy-MM-dd' instead.
We have this class:
public class SayHelloResponse {
private List<LocalDate> dates;
private String message;
public SayHelloResponse(String message, LocalDate... dates) {
this.message = message;
this.dates = ImmutableList.copyOf(dates);
}
public List<LocalDate> getDates() {
return dates;
}
public String getMessage() {
return message;
}
}
That results in this Model Schema:
{
"dates": [
"LocalDate"
],
"message": "string"
}
In the Model Schema, I would like to have LocalDate as 'date' or 'yyyy-MM-dd'. The way to do this seems to be with com.wordnik.swagger.annotations.ApiModelProperty but this does not have any effect (it is being picked up, as when I add #ApiModelProperty(hidden=true) it is hidden).
I created a sample rest project that shows the issue.
Any ideas how I can change LocalDate to 'date' or 'yyyy-MM-dd' in the Model Schema of Swagger?
There is a method in Docket object to replace models called directModelSubstitute(). You can use it like this to substitute LocalDate to Date object:
Docket#directModelSubstitute(LocalDate.class, Date.class)
The only problem with it that I found is that you can't change the date format.
See A/Q section in the official Springfox documentation, specifically question "How do we use Java 8 types esply. LocalDateTime?"
This is recommended in the official Springfox documentation, but doesn't effect:
Docket(DocumentationType.SWAGGER_2)..build().directModelSubstitute(LocalDate.class, java.sql.Date.class)
This effect but change format to date-time instead of date:
Docket(DocumentationType.SWAGGER_2)..build().directModelSubstitute(LocalDate.class, java.util.Date.class);
That's why I use the last one and ignore time part.