java - 如何将 Jackson TypeReference 用于泛型类

标签 java angularjs generics jackson

我是新来的,知道下面的问题可能已经讨论过很多次了,但我找不到解决我的问题的明确解决方案...

因此,我正在开发一个由两部分组成的应用程序: - AngularJS 的前端 - Spring MVC 的后端 两者都以 JSON 格式与 Jackson 进行交换。 将 JSON 关联到 View 对象 (VO)

所以我在 FrontEnd 上有下面的 Javascript 函数:

 		 /**
 		 * Reference save.
 		 * @param reference The reference to save
 		 * @param type Type of reference
 		 */
 		 save: function(reference,type) {
 		 	return $http.post('myApplication/reference/save/'+ type, reference);
 		 }

将数据发送到下面的 Java 函数:

         **
     * Reference Controller.
     * @param <VO> Reference
     * @param <E> Entity
     */
    @RequestMapping("/reference/")
    @Controller
    public class ReferenceController<VO extends AbstractReferenceEntityVO, E extends AbstractReferenceEntity> {

    /** Reference management service. */
    @Autowired
    private ReferenceService<VO, E> referenceService;

    /**
     * Reference save method.
     * @param referenceVO View Object of the reference to save
     * @param type Reference type
     * @return VO
     */
    @ResponseBody
    @RequestMapping(value = "/save/{type}", method = RequestMethod.POST,
            headers = "Accept=application/json")
    public VO save(@Validated @RequestBody final VO referenceVO,
            @PathVariable final String type)
    {
        return this.referenceService.save(type, referenceVO);

    }
}

这个JAVA类是一个通用类,因为这个 Controller 可以接收/发送2种ReferenceVO(VO1和VO2),两者都继承自抽象类(AbstractReferenceEntityVO)。

今天,我在尝试调用此保存函数时遇到了以下 jackson 问题:

    *Caused by: com.fasterxml.jackson.databind.JsonMappingException: Can not construct instance of myApplication.AbstractReferenceEntityVO, problem: abstract types either need to be mapped to concrete types, have custom deserializer, or be instantiated with additional type information
     at [Source: java.io.PushbackInputStream@1a956b3d; line: 1, column: 1]
        at com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:148)
        at com.fasterxml.jackson.databind.DeserializationContext.instantiationException(DeserializationContext.java:889)
        at 
com.fasterxml.jackson.databind.deser.AbstractDeserializer.deserialize(AbstractDeserializer.java:139)
    at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:3702)
    at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2798)
    at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.readJavaType(AbstractJackson2HttpMessageConverter.java:205)
    ... 88 more*

经过研究,我发现我必须使用 jackson“TypeReference”来管理 Generic 类。所以我想我必须向 Jackson 指定它必须用于映射的继承 VO,因此我需要首先对我的引用的“类型”执行一个条件以与正确的 VO 关联...

这是我的 ObjectMapper 和 XML 配置:

	<mvc:annotation-driven conversion-service="applicationConversionService">
	  	<mvc:message-converters>
			<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
 				<property name="objectMapper">
					<bean class="myApplication.CustomObjectMapper" />
				</property>
			</bean>
		</mvc:message-converters>
	</mvc:annotation-driven>

/**
 * Mapper JSON objets.
 */
public class CustomObjectMapper
    extends ObjectMapper
{
    /** Id. */
    private static final long serialVersionUID = 6488036405547458525L;

    /** Constructor. */
    public PlageObjectMapper()
    {
        super();
        this.registerModule(new JodaModule());
        this.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
        this.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);

        TypeReference ref = new TypeReference<AbstractReferenceEntityVO>() { 
            // if(type== "TYPE_1") {
            //    TODO
            // } else {
            //    TODO
            // }
        };
    }
}

有人已经必须做类似的事情了吗?或者如何在我的案例中使用 TypeReference ?老实说,我有点不知道该做什么!

非常感谢您的帮助!

最佳答案

您需要将类型标识符作为 json 中的字段传递。使用 @JsonTypeInfo 注释您的基类,以指定要使用的字段名称和标识符。默认情况下,如果您使用类名作为标识符,则字段名称为 @class

请参阅 wiki 页面 polymorphic deserialisation了解详情。

示例:

import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.xml.sax.SAXException;

import javax.xml.transform.TransformerException;
import java.io.IOException;

public class Scratch {

    private static ObjectMapper mapper = new ObjectMapper();

    public static void main(String[] args) throws IOException, TransformerException, SAXException {
        System.out.println(mapper.readValue("{\"@class\": \"Scratch$B\", \"payload\": \"hello, world.\"}", A.class));
        System.out.println(mapper.readValue("{\"@class\": \"Scratch$C\", \"payload\": \"hello again.\", \"extra\": 1}", A.class));
    }

    @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS)
    abstract public static class A {
        abstract public String getPayload();

        @Override
        public String toString() {
            try {
                return "I'm a " + getClass().getSimpleName() + ": " + mapper.writeValueAsString(this);
            } catch (JsonProcessingException e) {
                throw new RuntimeException(e);
            }
        }
    }

    public static class B extends A {
        private String payload;

        @Override
        public String getPayload() {
            return payload;
        }

        public void setPayload(String payload) {
            this.payload = payload;
        }
    }

    public static class C extends B {
        private int extra;

        public int getExtra() {
            return extra;
        }

        public void setExtra(int extra) {
            this.extra = extra;
        }
    }
}

关于java - 如何将 Jackson TypeReference 用于泛型类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40709429/

相关文章:

javascript - TextAngular 自定义工具栏按钮 onElementSelect 不适用于 table/tr/td

angularjs - ng-switch 和 ng-repeat 对同一元素进行干扰

c# - 你能在 Controller 中使用泛型方法吗?

java - Firebird 提交在 Java 应用程序中不起作用

java - 将类型 A 的类反序列化为具有相同 serialVersionUID 、字段、方法的类型 B

java - joda new DateTime(int,int,int,int,int,int)的问题

java - Hibernate 方言 + datediff 函数

javascript - Angular 中的 $document 和 $window.document 有什么区别?

java - 什么是原始类型,为什么我们不应该使用它呢?

java - 将泛型添加到 ArrayUtils.toMap