问题描述
我正在尝试序列化和反序列化一个包含 Object 类型字段的类。当我为该字段分配一个变量时,例如一个整数,则该类的序列化版本不包含任何类型信息,无论是否使用 JsonTypeInfo 注释。我不知道如何继续,所以如果有人能指出我正确的方向
完整代码可以在我的 github 上找到: https://github.com/Notedop/BusinessRuleValidator
我已经检查了这个 SO:java jackson keep type information after serialize if variable of type Object 但是这个解决方案对我不起作用,因为 objectToEvaluate 字段在序列化后仍然不包含类型信息。
Field objectToEvaluate 是 Object 类型,但分配了一个 Integer 类型。这在序列化中不可见,并在反序列化时导致问题。理论上它应该能够分配任何类型,并且能够在不丢失原始类型信息的情况下正确地序列化和反序列化。
<BusinessRuleSet _class="nl.rvh.rulevalidation.BusinessRuleSet">
<name>Check Golden Cross</name>
<operator>AND</operator>
<successResultApplicator _class="nl.rvh.rulevalidation.LogApplicator">
<parameters>
<log>the result is SUCCESS!</log>
</parameters>
</successResultApplicator>
<failResultApplicator _class="nl.rvh.rulevalidation.LogApplicator">
<parameters>
<log>the result is SUCCESS!</log>
</parameters>
</failResultApplicator>
<businessRules>
<businessRules _class="nl.rvh.rulevalidation.MaGoldenCross">
<comparisonoperator>GREATER_THAN</comparisonoperator>
<objectToEvaluate>2.0</objectToEvaluate>
<name>MaGoldenCross</name>
<successResultApplicator _class="nl.rvh.rulevalidation.LogApplicator">
<parameters>
<log>the result is SUCCESS!</log>
</parameters>
</successResultApplicator>
<failResultApplicator _class="nl.rvh.rulevalidation.LogApplicator">
<parameters>
<log>the result is SUCCESS!</log>
</parameters>
</failResultApplicator>
</businessRules>
<businessRules _class="nl.rvh.rulevalidation.MaGoldenCross">
<comparisonoperator>GREATER_THAN</comparisonoperator>
<objectToEvaluate>10000000</objectToEvaluate>
<name>MaGoldenCross</name>
<successResultApplicator _class="nl.rvh.rulevalidation.LogApplicator">
<parameters>
<log>the result is SUCCESS!</log>
</parameters>
</successResultApplicator>
<failResultApplicator _class="nl.rvh.rulevalidation.LogApplicator">
<parameters>
<log>the result is SUCCESS!</log>
</parameters>
</failResultApplicator>
</businessRules>
</businessRules>
我猜序列化和反序列化的工作是可行的,因为值被分配给了 Field objectToEvaluate,但是类型信息丢失了,反序列化后它是一个 String 类型存储为 Object 而不是存储为 Object 的 Integer 类型.
有一个名为 serializeAndDeserializeRuleSet() 的测试用例。此测试用例创建一个业务规则集,对其进行评估、序列化、反序列化,然后再次尝试对其进行评估。第二次运行时,由于反序列化问题导致类转换异常,它失败了。
出现问题的类是抽象 BusinessRule 类。该字段称为 objectToEvaluate
package nl.rvh.rulevalidation;
import com.fasterxml.jackson.annotation.*;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import nl.rvh.rulevalidation.enums.Comparisonoperator;
import javax.print.DocFlavor;
/**
* Abstract business rule class. Extend this class to implement custom business rule.
* The implementing class must contain a constructor having the @JsonCreator annotation
* and JsonProperty annotation on the constructor parameters to assure proper serialization
* and de-serialization.
*
* Implement the Evaluate method in the derived class. You can process the objectToEvaluate to your
* liking and then use the comparisonoperator.compare() method to do the final evaluation
*
*/
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS,property = "@class",visible = true)
public abstract class BusinessRule extends Rule {
@JacksonXmlProperty
protected Comparisonoperator comparisonoperator;
@JacksonXmlProperty
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS,visible = true)
protected Object objectToEvaluate;
@JsonCreator
protected BusinessRule(@JsonProperty("comparisonoperator") Comparisonoperator comparisonoperator,@JsonProperty("objectToEvaluate") Object objectToEvaluate,@JsonProperty("name") String name) {
super(name);
this.objectToEvaluate = objectToEvaluate;
this.comparisonoperator = comparisonoperator;
}
//getters and setters and stuff here
}
派生类如下:
package nl.rvh.rulevalidation;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import nl.rvh.rulevalidation.enums.Comparisonoperator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS,visible = true)
public class MaGoldenCross extends BusinessRule {
private Logger log = LoggerFactory.getLogger(MaGoldenCross.class);
@JsonCreator
public MaGoldenCross(@JsonProperty("comparisonoperator") Comparisonoperator comparisonoperator,@JsonProperty("objectToEvaluate") Object expectedValue) {
super(comparisonoperator,expectedValue,"MaGoldenCross");
}
@Override
boolean evaluate(Object objectToEvaluate) {
log.debug("Evaluating {} if {} is {} expected value {}",name,objectToEvaluate,comparisonoperator.getDescription(),this.objectToEvaluate);
//do some stuff to the objectToEvaluate,or directly pass it for evaluation
return comparisonoperator.compare(objectToEvaluate,getobjectToEvaluate());
}
}
测试用例
@Test
void serializeAndDeserializeRuleSet() throws JsonProcessingException {
XmlMapper xmlMapper = new XmlMapper();
getBusinessRuleSet().evaluate(6);
String xml = xmlMapper.writeValueAsstring(getBusinessRuleSet());
log.debug(xml);
BusinessRuleSet businessRuleSet = xmlMapper.readValue(xml,BusinessRuleSet.class);
log.debug("{}",businessRuleSet);
Assertions.assertTrue(businessRuleSet.evaluate(6)); // <---- FAILS as deserialized
}
private BusinessRuleSet getBusinessRuleSet() {
BusinessRuleSet businessRules = new BusinessRuleSet("Check Golden Cross",LogicalOperator.AND);
BusinessRule businessRule1 = new MaGoldenCross(GREATER_THAN,2.0);
BusinessRule businessRule2 = new MaGoldenCross(GREATER_THAN,10000000);
Map<String,Object> succesMap = new HashMap<>();
succesMap.put("log","the result is SUCCESS!");
LogApplicator successLogApplicator = new LogApplicator(succesMap);
LogApplicator failLogApplicator = new LogApplicator(succesMap);
businessRule1.setSuccessResultApplicator(successLogApplicator);
businessRule2.setSuccessResultApplicator(successLogApplicator);
businessRule1.setFailResultApplicator(failLogApplicator);
businessRule2.setFailResultApplicator(failLogApplicator);
businessRules.addRule(businessRule1);
businessRules.addRule(businessRule2);
businessRules.setSuccessResultApplicator(successLogApplicator);
businessRules.setFailResultApplicator(failLogApplicator);
return businessRules;
}
更新:
我一直在努力,但不幸的是,杰克逊仍然没有运气。作为最后的手段,我开始研究不同的序列化库。 xStream 能够完美地序列化/反序列化 java.lang.Object 并且仍然记住它的子类型信息。
public class SimplePojo {
Object canBeAnySubType;
public Object getCanBeAnySubType() {
return canBeAnySubType;
}
public void setCanBeAnySubType(Object canBeAnySubType) {
this.canBeAnySubType = canBeAnySubType;
}
}
@Test
void testdamnPojoWithXstream() {
SimplePojo pojo = new SimplePojo();
pojo.setCanBeAnySubType(new Integer(1));
XStream xstream = new XStream(new StaxDriver());
String xml = xstream.toXML(pojo);
log.debug(xml);
SimplePojo deserPojo = (SimplePojo) xstream.fromXML(xml);
if (deserPojo.getCanBeAnySubType() instanceof Integer)
log.debug("success");
}
2021-06-08 18:40:23:228 +0200 [main] DEBUG nl.rvh.rulevalidation.TestPojo - <?xml version='1.0' encoding='UTF-8'?><nl.rvh.rulevalidation.SimplePojo><canBeAnySubType class="int">1</canBeAnySubType></nl.rvh.rulevalidation.SimplePojo>
Security framework of XStream not explicitly initialized,using predefined black list on your own risk.
2021-06-08 18:40:23:251 +0200 [main] DEBUG nl.rvh.rulevalidation.TestPojo - success
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)