How to force Spring HATEOAS resources to render an empty embedded array? - spring

I have the following controller method:
#RequestMapping(produces = MediaType.APPLICATION_JSON_VALUE, value = "session/{id}/exercises")
public ResponseEntity<Resources<Exercise>> exercises(#PathVariable("id") Long id) {
Optional<Session> opt = sessionRepository.findWithExercises(id);
Set<Exercise> exercises = Sets.newLinkedHashSet();
if (opt.isPresent()) {
exercises.addAll(opt.get().getExercises());
}
Link link = entityLinks.linkFor(Session.class)
.slash(id)
.slash(Constants.Rels.EXERCISES)
.withSelfRel();
return ResponseEntity.ok(new Resources<>(exercises, link));
}
So basically I am trying to get the expose a Set<> of Exercise entities for a particular Session. When the exercises entity is empty however I get a JSON representation like this:
{
"_links": {
"self": {
"href": "http://localhost:8080/api/sessions/2/exercises"
}
}
}
So basically there is no embedded entity, while something like the following would be preferrable:
{
"_links": {
"self": {
"href": "http://localhost:8080/api/sessions/2/exercises"
}
},
"_embedded": {
"exercises": []
}
}
any idea how to enforce this?

The problem here is that without additional effort there's no way to find out that the empty collection is a collection for Exercise. Spring HATEOAS has a helper class to work around this though:
EmbeddedWrappers wrappers = new EmbeddedWrappers(false);
EmbeddedWrapper wrapper = wrappers.emptyCollectionOf(Exercise.class);
Resources<Object> resources = new Resources<>(Arrays.asList(wrapper));
An EmbeddedWrapper allows you to explicitly mark objects to be added to the Resource or Resources as embedded, potentially even manually defining the rel they should be exposed under. As you can see above the helper also allows you to add an empty collection of a given type to the _embedded clause.

One can use the PagedResourceAssembler::toEmptyResource() method. For example, the following works:
Page<EWebProduct> products = elasticSearchTemplate.queryForPage(query, EWebProduct.class);
if(!products.hasContent()){
PagedResources pagedResources = pageAssembler.toEmptyResource(products, WebProductResource.class,baseLink);
return new ResponseEntity<PagedResources<WebProductResource>>(pagedResources, HttpStatus.OK);
}
I'd bet it works with other ResourceAssemblers as well.

If you have a Page< T >, you can convert it like this:
public static <T> PagedModel<EntityModel<T>> toModel(PagedResourcesAssembler<T> assembler,
Page<T> page) {
if (!page.isEmpty()) {
return assembler.toModel(page);
} else {
// toEmptyModel renders the _embedded field (with an empty array inside)
return (PagedModel<EntityModel<T>>) assembler.toEmptyModel(page, TenantSubscriptionResponseDto.class);
}
}
(You can obtain the PagedResourcesAssembler assembler by simply adding it as a parameter to the Controller method, and Spring will inject it).

Spring by default uses Jackson parser to serialize/deserialize json. As per http://wiki.fasterxml.com/JacksonFeaturesSerialization Jackson has a feature called WRITE_EMPTY_JSON_ARRAYS and its enabled by default. Maybe WRITE_EMPTY_JSON_ARRAYS is set to false in your config. please recheck your message converters configuration.

Related

MapStruct Spring Page to custom object conversion includes check

I am using MapStruct to convert a Page object to a custom object of my application. I am using this mapping in order to convert the content field of the Page object to a list of custom objects found in my data model:
#Mapping(target = "journeys", source = "content")
While this works OK and does convert the elements when content is present, this does not work correctly in case of no Page content. Taking a look at the code seems to show that the following check is added in the generated mapper class:
if ( page.hasContent() ) {
List<JourneyDateViewResponseDto> list = page.getContent();
journeyDateViewPageResponseDto.setJourneys( new ArrayList<JourneyDateViewResponseDto>( list ) );
}
When this is added the mapping action of the inner objects is omitted, meaning that I end up with a null list. I am not really sure as to why and how this check is added but I would like to find a way of disabling it and simply end up with an empty list of elements. Is there a way this can be done using MapStruct?
MapStruct has the concept of presence checkers (methods that have the pattern hasXXX). This is used to decide if a source property needs to be mapped.
In case you want to have a default value in your object I would suggest making sure that your object is instantiated with an empty collection or provide an #ObjectFactory for your object in which you are going to set the empty collection.
e.g.
Default value in class
public class JourneyDateViewPageResponseDto {
protected List<JourneyDateViewResponseDto> journeys = new ArrayList<>();
//...
}
Using #ObjectFactory
#Mapper
public interface MyMapper {
JourneyDateViewPageResponseDto map(Page< JourneyDateViewResponseDto> page);
#ObjectFactory
default JourneyDateViewPageResponseDto createDto() {
JourneyDateViewPageResponseDto dto = new JourneyDateViewPageResponseDto();
dto.setJourneys(new ArrayList<>());
return dto;
}
}
#Mapping(target = "journeys", source = "content", defaultExpression = "java(java.util.List.of())")

How to retrieve data by property in Couchbase Lite?

My documents have the property docType that separated them based on the purpose of each type, in the specific case template or audit. However, when I do the following:
document.getProperty("docType").equals("template");
document.getProperty("docType").equals("audit");
The results of them are always the same, it returns every time all documents stored without filtering them by the docType.
Below, you can check the query function.
public static Query getData(Database database, final String type) {
View view = database.getView("data");
if (view.getMap() == null) {
view.setMap(new Mapper() {
#Override
public void map(Map<String, Object> document, Emitter emitter) {
if(String.valueOf(document.get("docType")).equals(type)){
emitter.emit(document.get("_id"), null);
}
}
}, "4");
}
return view.createQuery();
}
Any hint?
This is not a valid way to do it. Your view function must be pure (it cannot reference external state such as "type"). Once that is created you can then query it for what you want by setting start and end keys, or just a set of keys in general to filter on.

Dropwizard deserializing generic list from JerseyClient

I wanted to implement a generic class to use for caching results from a REST API in a local MongoDB-instance. For this to work, I need to deserialize a collection I get from JerseyClient:
Response response = this.source.request().get();
List<T> list = response.readEntity( new GenericType<List<T>>() {} );
// ... do stuff with the list
Let's say I'm using this piece of code in a context of T relating to a class Foo. The really weird thing is, after the readEntity call, list is not a List<Foo>, instead is a List<LinkedHashMap>. How is that even possible, when I've clearly declared the Generic T to be Foo?
What do I have to do to get a proper List<T>, i.e. List<Foo> instead?
Note: If I remove the generic, and use
List<Foo> list = response.readEntity( new GenericType<List<Foo>>() {} );
directly instead, it works fine, but I really need that generic to be there!
Java's most popular excuse for Generics: Type Erasure
If you can pass your class type as Class<T> clazz, then you can use this:
GenericType<List<T>> genericType = new GenericType<>(new ParameterizedType() {
public Type[] getActualTypeArguments() {
return new Type[]{clazz};
}
public Type getRawType() {
return List.class;
}
public Type getOwnerType() {
return null;
}
});
response.readEntity(genericType);
You can use
import sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl;
import javax.ws.rs.core.GenericType;
GenericType<List<T>> genericType = new GenericType<>(
ParameterizedTypeImpl.make( List.class, new Type[]{classType}, null));

Spring Restful issue with list of length 1

We are having a json which shows a list of object as below:
skillCheckAnswers: [
{
optionId: 6786,
optionText: "Copy constructor",
optionWeight: "1.00"
},
{
optionId: 6787,
optionText: "Friend constructor",
optionWeight: "2.00"
},
{
optionId: 6788,
optionText: "Default constructor",
optionWeight: "3.00"
},
{
optionId: 6789,
optionText: "Parameterized constructor",
optionWeight: "4.00"
}
]
Which is ok as long as there are more than 1 object in the list. But if the list contains only 1 item then the json displays :
{
optionId: 6785,
optionText: "Friend class",
optionWeight: "4.00"
}
Please note that the second Json is not given as a List but as a single object ( missing square braces[] ).
Is there a way where I can output the list of length 1 with square braces?
Edit--
We can use foreach for the first JSON but foreach starts giving error if the number of object goes to 1. To handle this we are having an if else loop to check if the List is of length 1 or more than 1. If the list is of length then we handle this as a single obkect. This seems to be a stupid solution and I guess there would be an easy way out.
Can anyone tell me if this is even possible?
You should do something like:
From Spring controller:
#RequestMapping(method = RequestMethod.GET, value = "/myquestions")
public #ResponseBody
List<Answer> generateQuestions() {
List<Answer> answers = new ArrayList<Answer>();
Answer ans1 = new Answer();
ans1.setOptionId("6785");
ans1.setOptionText("Friend class");
ans1.setOptionWeight("4.00");
answers.add(ans1);
return answers;
}
The output is as follows:
[
{
"optionId": "6785",
"optionText": "Friend class",
"optionWeight": "4.00"
}
]
So far I understood, you problem is related to JSON converter. I have tested with Spring MappingJacksonHttpMessageConverter message converter. You can see Spring documentation for how to configure the JSON converter. http://static.springsource.org/spring/docs/3.0.0.M3/reference/html/ch18s02.html
You mentioned you use Spring. Doesn't Spring automatically look after JSON conversions for your the restful API it provides. You can put something like this is your conext file:
You can use org.springframework.http.converter.json.MappingJacksonHttpMessageConverter and set it up in your context file to do the JSON conversion for you.
Then you can use Spring MVC's #ResponseBody annotation to provide a restful service with having to handcode the JSON response.

Using eager loading with specification pattern

I've implemented the specification pattern with Linq as outlined here https://www.packtpub.com/article/nhibernate-3-using-linq-specifications-data-access-layer
I now want to add the ability to eager load and am unsure about the best way to go about it.
The generic repository class in the linked example:
public IEnumerable<T> FindAll(Specification<T> specification)
{
var query = GetQuery(specification);
return Transact(() => query.ToList());
}
public T FindOne(Specification<T> specification)
{
var query = GetQuery(specification);
return Transact(() => query.SingleOrDefault());
}
private IQueryable<T> GetQuery(
Specification<T> specification)
{
return session.Query<T>()
.Where(specification.IsSatisfiedBy());
}
And the specification implementation:
public class MoviesDirectedBy : Specification<Movie>
{
private readonly string _director;
public MoviesDirectedBy(string director)
{
_director = director;
}
public override
Expression<Func<Movie, bool>> IsSatisfiedBy()
{
return m => m.Director == _director;
}
}
This is working well, I now want to add the ability to be able to eager load. I understand NHibernate eager loading can be done by using Fetch on the query.
What I am looking for is whether to encapsulate the eager loading logic within the specification or to pass it into the repository, and also the Linq/expression tree syntax required to achieve this (i.e. an example of how it would be done).
A possible solution would be to extend the Specification class to add:
public virtual IEnumerable<Expression<Func<T, object>>> FetchRelated
{
get
{
return Enumerable.Empty<Expression<Func<T, object>>>();
}
}
And change GetQuery to something like:
return specification.FetchRelated.Aggregate(
session.Query<T>().Where(specification.IsSatisfiedBy()),
(current, related) => current.Fetch(related));
Now all you have to do is override FetchRelated when needed
public override IEnumerable<Expression<Func<Movie, object>>> FetchRelated
{
get
{
return new Expression<Func<Movie, object>>[]
{
m => m.RelatedEntity1,
m => m.RelatedEntity2
};
}
}
An important limitation of this implementation I just wrote is that you can only fetch entities that are directly related to the root entity.
An improvement would be to support arbitrary levels (using ThenFetch), which would require some changes in the way we work with generics (I used object to allow combining different entity types easily)
You wouldn't want to put the Fetch() call into the specification, because it's not needed. Specification is just for limiting the data that can then be shared across many different parts of your code, but those other parts could have drastically different needs in what data they want to present to the user, which is why at those points you would add your Fetch statements.

Resources