Jackson MixIn用它后面的getValue()替换泛型类JAXBElement

时间:2021-01-02 18:05:51

I'm trying to bind XML and JSON using the same JAXB annotations (using the JaxbAnnotationModule).

我正在尝试使用相同的JAXB注释绑定XML和JSON(使用JaxbAnnotationModule)。

XML <--> JAXB <--> Jackson <--> JSON

I have to use the JAXB annotation and cannot alter them. My problem is that some XMLs convert to the generic class JAXBElement<T> instead of a class T directly. That leads to the JSON output:

我必须使用JAXB注释,不能改变它们。我的问题是一些XML直接转换为泛型类JAXBElement 而不是类T.这导致了JSON输出:

{  
   "JAXBElement":{  
      "name":"{http://www.opengis.net/wps/1.0.0}Capabilities",
      "declaredType":"net.opengis.wps.v_1_0_0.WPSCapabilitiesType",
      "scope":"javax.xml.bind.JAXBElement$GlobalScope",
      "value":{  
         "ProcessOfferings":{  },
         "Languages":{  },
         "ServiceIdentification":{  },
         "ServiceProvider":{  },
         "OperationsMetadata":{  },
         "version":"1.0.0",
         "updateSequence":"1",
         "service":"WPS",
         "lang":"en-US"
      },
      "nil":false,
      "globalScope":true,
      "typeSubstituted":false
   }
}

While I instead want:

虽然我想要:

{  
   "Capabilities":{  
     "ProcessOfferings":{  },
     "Languages":{  },
     "ServiceIdentification":{  },
     "ServiceProvider":{  },
     "OperationsMetadata":{  },
     "version":"1.0.0",
     "updateSequence":"1",
     "service":"WPS",
     "lang":"en-US"
   }
}

The real object of type T is wrapped by an JAXBElement. This may happen for some root elements and nested anywhere in the object tree as well. If I call getValue() on that I'll get the real object. But I can't do this when the JAXBElement<T> is not the root element since Jackson is the only interpreter between JAXB and JSON and I can neither alter the JAXB-Binding nor the created objects (some other parts of the code use them, too).

类型T的真实对象由JAXBElement包装。对于某些根元素可能会发生这种情况,并且嵌套在对象树中的任何位置。如果我调用getValue(),我将获得真实的对象。但是当JAXBElement 不是根元素时我不能这样做,因为Jackson是JAXB和JSON之间唯一的解释器,我既不能改变JAXB-Binding也不能改变创建的对象(代码的其他部分使用它们) ,也)。

So what I found what might solve the problem are MixIns:

所以我发现可能解决问题的是MixIns:

// a mixin annotation that overrides the handling for the JAXBElement
public static interface JAXBElementMixin<T> {
    @JsonValue
    Object getValue();
}

ObjectMapper mapper = new ObjectMapper();
JaxbAnnotationModule module = new JaxbAnnotationModule();
mapper.registerModule(module);
mapper.addMixInAnnotations(JAXBElement.class, JAXBElementMixin.class);

That solves the problem of the additional elements but causes the name of the object to be JAXBElement instead of T (in my case Capabilities):

这解决了附加元素的问题,但导致对象的名称是JAXBElement而不是T(在我的情况下是Capabilities):

{  
  "JAXBElement":{  // <------ Should be 'Capabilities' because of type JAXBElement<Capabilities>
    "ProcessOfferings":{  },
    "Languages":{  },
    "ServiceIdentification":{  },
    "ServiceProvider":{  },
    "OperationsMetadata":{  },
    "version":"1.0.0",
    "updateSequence":"1",
    "service":"WPS",
    "lang":"en-US"
  }
}

The questions:

问题:

Any idea what I can do (maybe annotate JAXBElementMixin<T>) to get the correct type Capabilities as object name (there are other classes instead of Capabilities that can be placed as T, too)?

知道我能做什么(可能注释JAXBElementMixin )以获得正确的类型Capabilities作为对象名称(还有其他类而不是可以作为T放置的Capabilities)?

Any other idea how to skip the serialization of any JAXBElement<T> anywhere in the object tree and continue with the serialization of the object behind its getValue() method?

还有其他想法如何在对象树中的任何地方跳过任何JAXBElement 的序列化并继续对其getValue()方法后面的对象进行序列化?

2 个解决方案

#1


0  

This is not directly an answer to your question, but possibly a recipe to achieve your goal.

这不是您问题的直接答案,但可能是实现目标的方法。

If you just want to get rid of the topmost JAXBElement, why don't you just customize XJC to generate an additional class for your Capabilities element?

如果你只想摆脱最顶层的JAXBElement,为什么不定制XJC为你的Capabilities元素生成一个额外的类?

Something like:

就像是:

<jaxb:bindings node="xs:element[@name='Capabilities']">
   <jaxb:class name="Capabilities"/>
</jaxb:bindings>

This should generate a class Capabilities annotated with '@XmlRootElement'. Thus you'll get rid of the JAXBElement.

这应该生成一个用'@XmlRootElement'注释的类功能。因此,您将摆脱JAXBElement。

#2


0  

Jackson does not support JAXBElement, as it is very much XML-specific and is difficult to make work with other formats: Jackson JAXB support is focused on using information from annotations to make things work, but goal is not to be a full JAXB implementation.

Jackson不支持JAXBElement,因为它非常特定于XML并且很难与其他格式一起工作:Jackson JAXB支持专注于使用注释中的信息来使事情有效,但目标不是完整的JAXB实现。

As such your best bet is to do what @lexicore suggests and try to avoid use of JAXBElement.

因此,最好的办法是做@lexicore建议并尝试避免使用JAXBElement。

#1


0  

This is not directly an answer to your question, but possibly a recipe to achieve your goal.

这不是您问题的直接答案,但可能是实现目标的方法。

If you just want to get rid of the topmost JAXBElement, why don't you just customize XJC to generate an additional class for your Capabilities element?

如果你只想摆脱最顶层的JAXBElement,为什么不定制XJC为你的Capabilities元素生成一个额外的类?

Something like:

就像是:

<jaxb:bindings node="xs:element[@name='Capabilities']">
   <jaxb:class name="Capabilities"/>
</jaxb:bindings>

This should generate a class Capabilities annotated with '@XmlRootElement'. Thus you'll get rid of the JAXBElement.

这应该生成一个用'@XmlRootElement'注释的类功能。因此,您将摆脱JAXBElement。

#2


0  

Jackson does not support JAXBElement, as it is very much XML-specific and is difficult to make work with other formats: Jackson JAXB support is focused on using information from annotations to make things work, but goal is not to be a full JAXB implementation.

Jackson不支持JAXBElement,因为它非常特定于XML并且很难与其他格式一起工作:Jackson JAXB支持专注于使用注释中的信息来使事情有效,但目标不是完整的JAXB实现。

As such your best bet is to do what @lexicore suggests and try to avoid use of JAXBElement.

因此,最好的办法是做@lexicore建议并尝试避免使用JAXBElement。