I'm using Spring-MVC, Spring-data-jpa, jackson on a Jhipster project.
I managed to use the @JsonView
annotation on an object and it works well when the method in the rest controller return a type ResponseEntity<List<MyObject>>
but I can't make it work when the method return type is ResponseEntity<Page<MyObject>>
.
I've tried to set MapperFeature.DEFAULT_VIEW_INCLUSION
to true (which default is false). When I do it, all attributes are serialized. But filtering through @JsonView
does not work anymore.
I can't modify the Page
object because it's a Spring-data object.
I'm looking for a way to tell jackson to include all attributes of the Page
object.
Here is my code:
My entity:
@Entity
@Table(name = "T_REGION")
public class Region implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Column(name = "code", nullable = false)
private Integer code;
@Column(name = "name", length = 60, nullable = false)
@JsonView(View.Summary.class)
private String name;
// Getters and setters
}
My rest controller:
@RestController
@RequestMapping("/api")
public class RegionResource {
@RequestMapping(value = "/regionsearch1",
method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE)
@JsonView(View.Summary.class)
public ResponseEntity<Page<Region>> findAll1(
@RequestParam(value = "page" , required = false) Integer offset,
@RequestParam(value = "per_page", required = false) Integer limit,
Sort sort)
throws URISyntaxException {
Pageable pageRequest = PaginationUtil.generatePageRequest(offset, limit, sort);
Page<Region> page = regionRepository.findAll(pageRequest);
HttpHeaders headers = PaginationUtil.generatePaginationHttpHeaders(page, "/api/regionsearch1", pageRequest);
return new ResponseEntity<>(page, headers, HttpStatus.OK);
}
@RequestMapping(value = "/regionsearch2",
method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE)
@JsonView(View.Summary.class)
public ResponseEntity<List<Region>> findAll2(
@RequestParam(value = "page" , required = false) Integer offset,
@RequestParam(value = "per_page", required = false) Integer limit,
Sort sort)
throws URISyntaxException {
Pageable pageRequest = PaginationUtil.generatePageRequest(offset, limit, sort);
Page<Region> page = regionRepository.findAll(pageRequest);
HttpHeaders headers = PaginationUtil.generatePaginationHttpHeaders(page, "/api/regionsearch2", pageRequest);
return new ResponseEntity<>(page.getContent(), headers, HttpStatus.OK);
}
}
findAll1
returns:
[
{
"name": "Ile-de-France"
},
{
"name": "Champagne-Ardenne"
},
....
]
findAll2
returns:
{}
The object Page
has no @JsonView
on its attributes therefore no attributes are serialized.
I can't find a way to tell Jackson to include all Page
attributes even when @JsonView
is used.
Any ideas ?
Another way to return all page elements is to create your own implementation for the Page interface (including the JsonView you want):
JsonPage
public class JsonPage<T> extends org.springframework.data.domain.PageImpl<T> {
public JsonPage(final List<T> content, final Pageable pageable, final long total) {
super(content, pageable, total);
}
public JsonPage(final List<T> content) {
super(content);
}
public JsonPage(final Page<T> page, final Pageable pageable) {
super(page.getContent(), pageable, page.getTotalElements());
}
@JsonView(JsonViews.UiView.class)
public int getTotalPages() {
return super.getTotalPages();
}
@JsonView(JsonViews.UiView.class)
public long getTotalElements() {
return super.getTotalElements();
}
@JsonView(JsonViews.UiView.class)
public boolean hasNext() {
return super.hasNext();
}
@JsonView(JsonViews.UiView.class)
public boolean isLast() {
return super.isLast();
}
@JsonView(JsonViews.UiView.class)
public boolean hasContent() {
return super.hasContent();
}
@JsonView(JsonViews.UiView.class)
public List<T> getContent() {
return super.getContent();
}
}
Next return this class to the controller layer:
Service
@Override
public Page<User> findAll(final int page) {
PageRequest pr = new PageRequest(page, pageSize, new Sort(Sort.Direction.DESC, "dateCreated"));
return new JsonPage<User>(userRepository.findAll(pr), pr);
}
Controller
@JsonView(JsonViews.UiView.class)
@RequestMapping(method = RequestMethod.GET, value = "{page}")
public Page<User> getUsers(@PathVariable final int page) {
return userService.findAll(page);
}
I have done like this , it's working well
package com.natixis.spring.ws.configuration;
import java.io.IOException;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.domain.Page;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializerProvider;
@Configuration
public class JacksonAdapter extends WebMvcConfigurerAdapter {
@Bean
public Jackson2ObjectMapperBuilder jacksonBuilder() {
return new Jackson2ObjectMapperBuilder()
.failOnUnknownProperties(false)
.serializationInclusion(Include.NON_EMPTY)
.serializerByType(Page.class, new JsonPageSerializer());
}
public class JsonPageSerializer extends JsonSerializer<Page<?>>{
@Override
public void serialize(Page<?> page, JsonGenerator jsonGen, SerializerProvider serializerProvider) throws IOException, JsonProcessingException {
ObjectMapper om = new ObjectMapper()
.disable(MapperFeature.DEFAULT_VIEW_INCLUSION)
.setSerializationInclusion(Include.NON_EMPTY);
jsonGen.writeStartObject();
jsonGen.writeFieldName("size");
jsonGen.writeNumber(page.getSize());
jsonGen.writeFieldName("number");
jsonGen.writeNumber(page.getNumber());
jsonGen.writeFieldName("totalElements");
jsonGen.writeNumber(page.getTotalElements());
jsonGen.writeFieldName("last");
jsonGen.writeBoolean(page.isLast());
jsonGen.writeFieldName("totalPages");
jsonGen.writeNumber(page.getTotalPages());
jsonGen.writeObjectField("sort", page.getSort());
jsonGen.writeFieldName("first");
jsonGen.writeBoolean(page.isFirst());
jsonGen.writeFieldName("numberOfElements");
jsonGen.writeNumber(page.getNumberOfElements());
jsonGen.writeFieldName("content");
jsonGen.writeRawValue(om.writerWithView(serializerProvider.getActiveView())
.writeValueAsString(page.getContent()));
jsonGen.writeEndObject();
}
}
}
Regards,
Régis LIMARE
I know this is an old question, but you can use something like this for a Page of objects
@Configuration
public class JacksonAdapter implements WebMvcConfigurer {
@Bean
public Jackson2ObjectMapperBuilder jacksonBuilder() {
return new Jackson2ObjectMapperBuilder().failOnUnknownProperties(false).serializerByType(Page.class,
new JsonPageSerializer());
}
public class JsonPageSerializer extends JsonSerializer<Page> {
@Override
public void serialize(Page page, JsonGenerator jsonGen, SerializerProvider serializerProvider)
throws IOException {
ObjectMapper om = new ObjectMapper().disable(MapperFeature.DEFAULT_VIEW_INCLUSION);
jsonGen.writeStartObject();
jsonGen.writeFieldName("size");
jsonGen.writeNumber(page.getSize());
jsonGen.writeFieldName("number");
jsonGen.writeNumber(page.getNumber());
jsonGen.writeFieldName("totalElements");
jsonGen.writeNumber(page.getTotalElements());
jsonGen.writeFieldName("last");
jsonGen.writeBoolean(page.isLast());
jsonGen.writeFieldName("totalPages");
jsonGen.writeNumber(page.getTotalPages());
jsonGen.writeObjectField("sort", page.getSort());
jsonGen.writeFieldName("first");
jsonGen.writeBoolean(page.isFirst());
jsonGen.writeFieldName("numberOfElements");
jsonGen.writeNumber(page.getNumberOfElements());
jsonGen.writeFieldName("content");
jsonGen.writeRawValue(
om.writerWithView(serializerProvider.getActiveView()).writeValueAsString(page.getContent()));
jsonGen.writeEndObject();
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With