Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of org.springframework.data.domain.Sort out of START_ARRAY token

My objectMapper is fetching the value of type Page<User> as follows:

userList = objectMapper.readValue(RestAdapter.get(url), new TypeReference<PageImplBean<User>>(){});

The PageImplBean extends PageImpl class as follows:

public class PageImplBean<T> extends PageImpl<T> {
private static final long serialVersionUID = 1L;
private int number;
private int size;
private int totalPages;
private int numberOfElements;
private long totalElements;
private boolean previousPage;
private boolean first;
private boolean nextPage;
private boolean last;
private List<T> content;
private Sort sort;

public PageImplBean() {
    super(new ArrayList<T>());
}

public int getNumber() {
    return number;
}

public void setNumber(int number) {
    this.number = number;
}

public int getSize() {
    return size;
}

public void setSize(int size) {
    this.size = size;
}

public int getTotalPages() {
    return totalPages;
}

public void setTotalPages(int totalPages) {
    this.totalPages = totalPages;
}

public int getNumberOfElements() {
    return numberOfElements;
}

public void setNumberOfElements(int numberOfElements) {
    this.numberOfElements = numberOfElements;
}

public long getTotalElements() {
    return totalElements;
}

public void setTotalElements(long totalElements) {
    this.totalElements = totalElements;
}

public boolean isPreviousPage() {
    return previousPage;
}

public void setPreviousPage(boolean previousPage) {
    this.previousPage = previousPage;
}



public boolean isNextPage() {
    return nextPage;
}

public void setNextPage(boolean nextPage) {
    this.nextPage = nextPage;
}


public boolean isFirst() {
    return first;
}

public void setFirst(boolean first) {
    this.first = first;
}

public boolean isLast() {
    return last;
}

public void setLast(boolean last) {
    this.last = last;
}

public List<T> getContent() {
    return content;
}

public void setContent(List<T> content) {
    this.content = content;
}

public Sort getSort() {
    return sort;
}

public void setSort(Sort sort) {
    this.sort = sort;
}

public PageImpl<T> pageImpl() {
    return new PageImpl<T>(getContent(), new PageRequest(getNumber(),
            getSize(), getSort()), getTotalElements());
}
}

My repository class looks as follows:

@EnableScan
@EnableScanCount
public abstract interface UserRepository extends PagingAndSortingRepository<User, String>
{
  public abstract Page<User> findByAddressId(String paramString, Pageable paramPageable);

  public abstract Page<User> findAll(Pageable paramPageable);
}    

My service class is as follows:

public Page<User> fetchUserList(String addressId,Integer pageNumber, Integer pageSize){
    Page<User> userPageList = null;

        PageRequest pageRequest = new PageRequest(pageNumber - 1, pageSize, Direction.ASC, "addressId");
        userPageList = userRepository.findByAddressId(addressId, pageRequest);

    return userPageList;
}

My Page<User> object from the webservice consists of a pageable instance with object Sort which consists of value [addressId: ASC].

While deserializing the object to userList with objectMapper as shown above I'm encountering the mentioned error.

com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of org.springframework.data.domain.Sort out of START_ARRAY token

Any help much appreciated. Thank you.

like image 919
Manoj Paul Avatar asked Jun 22 '15 07:06

Manoj Paul


People also ask

Why do I get an exception when deserializing a JSON string?

This exception is thrown if there is an unknown property in the JSON String while deserializing. We'll try to deserialize a JSON String with extra property “ checked “:

Why does Jackson throw this exception when deserializing an abstract class?

This exception is thrown if Jackson can't create an instance of the class, which happens if the class is abstract or it is just an interface. Here we'll try to deserialize an instance from class Zoo that has a property animal with abstract type Animal:

Is there A Serializer for jsonmappingexception?

JsonMappingException: No Serializer Found for Class 5.1. The Problem Now let's take a look at JsonMappingException: No Serializer Found for Class. This exception is thrown if we try to serialize an instance while its properties and their getters are private.

What is the jsonmappingexception thrown by Jackson?

This exception is thrown if the JSON doesn't match exactly what Jackson is looking for. For example, the main JSON could be wrapped: 4.2. The Solution We can solve this problem using the annotation @JsonRootName: When we try to deserialize the wrapped JSON, it works correctly: 5. JsonMappingException: No Serializer Found for Class 5.1. The Problem


1 Answers

I ran into this exact issue this morning.

CustomSortDeserializer

import java.io.IOException;

import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.domain.Sort.Order;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;

public class CustomSortDeserializer extends JsonDeserializer<Sort> {

@Override
public Sort deserialize(JsonParser jp, DeserializationContext ctxt)
        throws IOException, JsonProcessingException {
    ArrayNode node = jp.getCodec().readTree(jp);
    Order[] orders = new Order[node.size()];
    int i = 0;
    for(JsonNode obj : node){
        orders[i] =  new Order(Direction.valueOf(obj.get("direction").asText()), obj.get("property").asText());
        i++;
    }
    Sort sort = new Sort(orders);
    return sort;
}

Then added the following the the PageImplBean's public void setSort(Sort sort) method:

@JsonDeserialize(using=CustomSortDeserializer.class)
public void setSort(Sort sort) {
    this.sort = sort;
}

Edit:

Here is the JSON I received to deserialize (from spring-data-commons - 1.9.2.RELEASE):

[
  {
    "direction": "ASC",
    "property": "amount",
    "ignoreCase": false,
    "nullHandling": "NATIVE",
    "ascending": true
  },
  {
    "direction": "ASC",
    "property": "effectiveDate",
    "ignoreCase": false,
    "nullHandling": "NATIVE",
    "ascending": true
  }
]

If you look at Sort, you'll see that it implements Iteratable for Order. And if you examine Order defined in the same class, you'll see the fields in my example JSON. So when Sort is serialized, it is serialized as a list of Order, which is why deserializing into Sort needs a custom deserializer implementation, and also why deserializing without a custom implementation fails (because it's trying to deserialize an array into a single object).

During deserialization, when a setter annotated with @JsonDeserializer is encountered as each property is deserialized, Jackson uses the supplied deserializer to deserialize that specific property.

like image 113
Morse Code Avatar answered Oct 30 '22 12:10

Morse Code