Ответ 1
Попробуйте зарегистрировать подтип, используя ObjectMapper.registerSubtypes
вместо использования аннотаций
У меня есть следующая объектная модель в моем веб-приложении Spring MVC (v3.2.0.RELEASE):
public class Order {
private Payment payment;
}
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = As.WRAPPER_OBJECT)
@JsonSubTypes.Type(name = "creditCardPayment", value = CreditCardPayment.class)
public interface Payment {}
@JsonTypeName("creditCardPayment")
public class CreditCardPayment implements Payment {}
Когда я сериализую класс Order в JSON, я получаю следующий результат (именно это я хочу):
{
"payment" : {
"creditCardPayment": {
...
}
}
К сожалению, если я возьму вышеуказанный JSON и попытаюсь де-сериализовать его обратно в мою объектную модель, я получаю следующее исключение:
Не удалось прочитать JSON: не удалось разрешить идентификатор типа 'creditCardPayment' в подтип [простой тип, класс Оплата] в [Источник: [email protected]; линия 1, столбец: 58] (через ссылочную цепочку: Order [ "payment" ]); вложенными exception is com.fasterxml.jackson.databind.JsonMappingException: Не удалось разрешить идентификатор типа 'creditCardPayment' в подтип [простой тип, класс Оплата] в [Источник: [email protected]; линия 1, столбец: 58] (через цепочку ссылок: Order [ "payment" ])
Мое приложение настроено через Spring JavaConf, как показано ниже:
@Configuration
@EnableWebMvc
public class AppWebConf extends WebMvcConfigurerAdapter {
@Bean
public ObjectMapper objectMapper() {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setSerializationInclusion(Include.NON_NULL);
objectMapper.configure(MapperFeature.DEFAULT_VIEW_INCLUSION, false);
return objectMapper;
}
@Bean
public MappingJackson2HttpMessageConverter mappingJacksonMessageConverter() {
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
converter.setObjectMapper(objectMapper());
return converter;
}
@Bean
public Jaxb2RootElementHttpMessageConverter jaxbMessageConverter() {
return new Jaxb2RootElementHttpMessageConverter();
}
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(jaxbMessageConverter());
converters.add(mappingJacksonMessageConverter());
}
}
Для тестирования у меня есть контроллер с двумя методами, один возвращает запрос на запрос HTTP для GET (этот работает) и тот, который принимает заказ через HTTP POST (этот не удается), например
@Controller
public class TestController {
@ResponseBody
@RequestMapping(value = "/test", method = RequestMethod.GET)
public Order getTest() {}
@RequestMapping(value = "/test", method = RequestMethod.POST)
public void postTest(@RequestBody order) {}
}
Я пробовал все предложения из различных обсуждений по SO, но пока не повезло. Может ли кто-нибудь определить, что я делаю неправильно?
Попробуйте зарегистрировать подтип, используя ObjectMapper.registerSubtypes
вместо использования аннотаций
Используется метод registerSubtypes()
!
@JsonTypeInfo(use=JsonTypeInfo.Id.NAME, include=JsonTypeInfo.As.PROPERTY, property="type")
public interface Geometry {
//...
}
public class Point implements Geometry{
//...
}
public class Polygon implements Geometry{
//...
}
public class LineString implements Geometry{
//...
}
GeoJson geojson= null;
ObjectMapper mapper = new ObjectMapper();
mapper.disable(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES);
mapper.registerSubtypes(Polygon.class,LineString.class,Point.class);
try {
geojson=mapper.readValue(source, GeoJson.class);
} catch (IOException e) {
e.printStackTrace();
}
Примечание1: Мы используем интерфейс и реализующие классы. Я хочу, чтобы Джексон де-сериализовал классы в соответствии с их классами реализации, вы должны зарегистрировать их все, используя метод ObjectMapper "registerSubtypes".
Примечание2: Кроме того, вы используете "@JsonTypeInfo (use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property =" type ")" в качестве аннотации к вашему интерфейсу.
Вы также можете определить порядок свойств, когда mapper записывает значение вашего POJO в качестве json.
Это можно сделать, используя аннотацию ниже.
@JsonPropertyOrder({"type","crs","version","features"})
public class GeoJson {
private String type="FeatureCollection";
private List<Feature> features;
private String version="1.0.0";
private CRS crs = new CRS();
........
}
Надеюсь, это поможет!
У меня была аналогичная проблема при работе с сервисом на основе dropwizard. Я не совсем понимаю, почему что-то не работает для меня так же, как работает код dropwizard, но я знаю, почему код в исходном сообщении не работает. @JsonSubTypes
требуется массив подтипов, а не одно значение. Поэтому, если вы замените строку...
@JsonSubTypes.Type(name = "creditCardPayment", value = CreditCardPayment.class)
с...
@JsonSubTypes({ @JsonSubTypes.Type(name = "creditCardPayment", value = CreditCardPayment.class) })
Я верю, что ваш код будет работать.
Для тех, кто имеет такое же сообщение об ошибке, может возникнуть проблема с обнаруженными подтипами. Попробуйте добавить строку, подобную приведенной выше, или искать проблему с открытием классов, в которых есть тег @JsonTypeName
.
Ответ Rashmin работал, и я нашел альтернативный способ избежать проблемы com.fasterxml.jackson.databind.JsonMappingException: Could not resolve type id into a subtype of Blah
без использования registerSubtypes
. Что вы можете сделать, так это добавить в родительский класс следующую аннотацию:
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "type")
Обратите внимание, что разница JsonTypeInfo.Id.CLASS
вместо JsonTypeInfo.Id.NAME
. Недостатком является то, что созданный JSON будет содержать все имя класса, включая полное пространство имен. Положительным моментом является то, что вам не нужно беспокоиться о регистрации подтипов.
Обнаружена та же ошибка и используется эквивалент (вместо того, чтобы CreditCardPayment использовал мое имя класса) ниже JSON в качестве входа для Deserializer и он работал.
{ "тип": "CreditCardPayment", ..... }
В моем случае я добавил defaultImpl = SomeClass.class
в @JsonTypeInfo и пытался его преобразовать SomeClass2.class