0

When I try to get a list of values using RestTemplate, I get an error. I use Spring 3.0.0.

Caused by: org.springframework.web.client.RestClientException: Error while extracting response for type [class [Lru.sandwichcloud.Ingredient;] and content type [application/json] at org.springframework.web.client.HttpMessageConverterExtractor.extractData(HttpMessageConverterExtractor.java:118) ~[spring-web-6.0.2.jar!/:6.0.2] at org.springframework.web.client.RestTemplate$ResponseEntityResponseExtractor.extractData(RestTemplate.java:1132) ~[spring-web-6.0.2.jar!/:6.0.2] at org.springframework.web.client.RestTemplate$ResponseEntityResponseExtractor.extractData(RestTemplate.java:1115) ~[spring-web-6.0.2.jar!/:6.0.2] at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:865) ~[spring-web-6.0.2.jar!/:6.0.2] at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:764) ~[spring-web-6.0.2.jar!/:6.0.2] at org.springframework.web.client.RestTemplate.getForEntity(RestTemplate.java:405) ~[spring-web-6.0.2.jar!/:6.0.2] at ru.sandwichcloud.SandwichCloudClient.getAllIngredients(SandwichCloudClient.java:42) ~[classes!/:0.0.7-SNAPSHOT] at ru.sandwichcloud.RestExamples.lambda$fetchIngredients$0(RestExamples.java:34) ~[classes!/:0.0.7-SNAPSHOT] at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:767) ~[spring-boot-3.0.0.jar!/:3.0.0] 11 common frames omitted Caused by: org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot deserialize value of type [Lru.sandwichcloud.Ingredient; from Object value (token JsonToken.START_OBJECT) at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.readJavaType(AbstractJackson2HttpMessageConverter.java:406) ~[spring-web-6.0.2.jar!/:6.0.2] at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.read(AbstractJackson2HttpMessageConverter.java:354) ~[spring-web-6.0.2.jar!/:6.0.2] at org.springframework.web.client.HttpMessageConverterExtractor.extractData(HttpMessageConverterExtractor.java:103) ~[spring-web-6.0.2.jar!/:6.0.2] 19 common frames omitted Caused by: com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize value of type [Lru.sandwichcloud.Ingredient; from Object value (token JsonToken.START_OBJECT) at [Source: (org.springframework.util.StreamUtils$NonClosingInputStream); line: 1, column: 1] at com.fasterxml.jackson.databind.exc.MismatchedInputException.from(MismatchedInputException.java:59) ~[jackson-databind-2.14.1.jar!/:2.14.1] at com.fasterxml.jackson.databind.DeserializationContext.reportInputMismatch(DeserializationContext.java:1746) ~[jackson-databind-2.14.1.jar!/:2.14.1] at com.fasterxml.jackson.databind.DeserializationContext.handleUnexpectedToken(DeserializationContext.java:1520) ~[jackson-databind-2.14.1.jar!/:2.14.1] at com.fasterxml.jackson.databind.DeserializationContext.handleUnexpectedToken(DeserializationContext.java:1467) ~[jackson-databind-2.14.1.jar!/:2.14.1] at com.fasterxml.jackson.databind.deser.std.ObjectArrayDeserializer.handleNonArray(ObjectArrayDeserializer.java:345) ~[jackson-databind-2.14.1.jar!/:2.14.1] at com.fasterxml.jackson.databind.deser.std.ObjectArrayDeserializer.deserialize(ObjectArrayDeserializer.java:196) ~[jackson-databind-2.14.1.jar!/:2.14.1] at com.fasterxml.jackson.databind.deser.std.ObjectArrayDeserializer.deserialize(ObjectArrayDeserializer.java:26) ~[jackson-databind-2.14.1.jar!/:2.14.1] at com.fasterxml.jackson.databind.deser.DefaultDeserializationContext.readRootValue(DefaultDeserializationContext.java:323) ~[jackson-databind-2.14.1.jar!/:2.14.1] at com.fasterxml.jackson.databind.ObjectReader._bindAndClose(ObjectReader.java:2105) ~[jackson-databind-2.14.1.jar!/:2.14.1] at com.fasterxml.jackson.databind.ObjectReader.readValue(ObjectReader.java:1481) ~[jackson-databind-2.14.1.jar!/:2.14.1] at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.readJavaType(AbstractJackson2HttpMessageConverter.java:395) ~[spring-web-6.0.2.jar!/:6.0.2] 21 common frames omitted

This is how JSON object looks like for "http://localhost:8080/data-api/ingredients":

  "_embedded" : {
    "ingredients" : [ {
      "name" : "Dark Bread",
      "type" : "BREAD",
      "_links" : {
        "self" : {
          "href" : "http://localhost:8080/data-api/ingredients/DARK"
        },
        "ingredient" : {
          "href" : "http://localhost:8080/data-api/ingredients/DARK"
        }
      }
    }, {
      "name" : "White Bread",
      "type" : "BREAD",
      "_links" : {
        "self" : {
          "href" : "http://localhost:8080/data-api/ingredients/WHTE"
        },
        "ingredient" : {
          "href" : "http://localhost:8080/data-api/ingredients/WHTE"
        }
      }
    }, {
      "name" : "Beef",
      "type" : "PROTEIN",
      "_links" : {
        "self" : {
          "href" : "http://localhost:8080/data-api/ingredients/BEEF"
        },
        "ingredient" : {
          "href" : "http://localhost:8080/data-api/ingredients/BEEF"
        }
      }
    }, {
      "name" : "Mustard",
      "type" : "SAUCE",
      "_links" : {
        "self" : {
          "href" : "http://localhost:8080/data-api/ingredients/MTRD"
        },
        "ingredient" : {
          "href" : "http://localhost:8080/data-api/ingredients/MTRD"
        }
      }
    } ]
  },
  "_links" : {
    "self" : {
      "href" : "http://localhost:8080/data-api/ingredients"
    },
    "profile" : {
      "href" : "http://localhost:8080/data-api/profile/ingredients"
    }
  }
}

How I try to get an object:

public List<Ingredient> getAllIngredients() {
    return rest.exchange("http://localhost:8080/data-api/ingredients",
                    HttpMethod.GET,
                    null,
                    new ParameterizedTypeReference<List<Ingredient>>() {}
            ).getBody();
}

Ingredient:

@Data
@RequiredArgsConstructor
@NoArgsConstructor(access=AccessLevel.PRIVATE, force=true)
@Entity
public class Ingredient {

  @Id
  private final String id;
  private final String name;
  private final Type type;

  public enum Type {
    BREAD, PROTEIN, VEGGIES, CHEESE, SAUCE
  }

}

When I get only one object by Id getIngredientById("BEEF"), it works fine. What am I doing wrong?

public Ingredient getIngredientById(String ingredientId) {

    return rest.getForObject(
            "http://localhost:8080/data-api/ingredients/{id}",
            Ingredient.class,
            ingredientId);
}

JSON from "http://localhost:8080/data-api/ingredients/BEEF"

{
  "name" : "Beef",
  "type" : "PROTEIN",
  "_links" : {
    "self" : {
      "href" : "http://localhost:8080/data-api/ingredients/BEEF"
    },
    "ingredient" : {
      "href" : "http://localhost:8080/data-api/ingredients/BEEF"
    }
  }
}

2 Answers 2

0

The one problem I can see when the list is being returned it has "_embedded" : { } element as root, so when you deserialize the response to List<Ingradient>it will not work. For single object it is working because you have response with Ingredient {} element is at the root. Either you need to get rid of _embadded from the API response or you have your object modified to incorporate exact structure you received from "http://localhost:8080/data-api/ingredients" API

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you! I used Traverson library and it ignored "_embedded" well!
0

Understanding exchang method

When you passing ParameterizedTypeReference<?> as response, it returns ResponseEntity

Instead of

public List<Ingredient> getAllIngredients() {
    return rest.exchange("http://localhost:8080/data-api/ingredients",
                    HttpMethod.GET,
                    null,
                    new ParameterizedTypeReference<List<Ingredient>>() {}
            ).getBody();
}

Try this using ResponseEntity

public List<Ingredient> getAllIngredients() {
    ResponseEntity<List<Ingredient>> result = restTemplate.exchange("http://localhost:8080/data-api/ingredients", HttpMethod.GET, null, new ParameterizedTypeReference<List<Ingredient>>() {});
    List<Ingredient> list = result.getBody();
    return list;

}

1 Comment

Thanks, but there is also getBody() in my code

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.