java JAXB:在没有@XmlJavaTypeAdapter 的情况下不能使用 XmlAdapter 吗?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6857166/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 17:36:59  来源:igfitidea点击:

JAXB: Isn't it possible to use an XmlAdapter without @XmlJavaTypeAdapter?

javajaxbadapter

提问by java.is.for.desktop.indeed

Can't I register a bunch of XmlAdapters to Marshaller|Unmarshallerso that I wouldn't need to specify @XmlJavaTypeAdapteron each filed, whose type isn't natively JAXB-supported?

我不能注册一堆XmlAdapters到Marshaller| Unmarshaller这样我就不需要@XmlJavaTypeAdapter在每个字段上指定,其类型本身不是 JAXB 支持的?

I find it somewhat redundant.

我觉得有点多余

BTW, someMarshaller.setAdapter(...)seem not to do anything.

BTW,someMarshaller.setAdapter(...)好像什么都没做。

回答by user1128134

This is a quite a good question !

这是一个很好的问题!

The short answer is that no, using setAdapteron marshaller / unmarshaller does not mean that you don't have to use @XmlJavaTypeAdapter.

简短的回答是setAdapter在 marshaller / unmarshaller 上使用并不意味着您不必使用@XmlJavaTypeAdapter.

Let me explain this with a hypothetical (yet valid!) scenario.

让我用一个假设的(但有效的!)场景来解释这一点。

Consider in a web application, one fetches an event in the form of xml having following schema:

考虑在 Web 应用程序中,以具有以下架构的 xml 形式获取事件:

<xs:element name="event" >
    <xs:complexType>
        <xs:sequence>
           <!-- Avoiding other elements for concentrating on our adapter -->
            <xs:element name="performedBy" type="xs:string" />   
        </xs:sequence> 
    </xs:complexType>  
</xs:element>

Equivalent to this, your model will look like:

等效于此,您的模型将如下所示:

@XmlRootElement(name="event")
@XmlType(name="")
public class Event {

     @XmlElement(required=true)
     protected String performedBy;
}

Now the application is already having a bean called Userwhich maintains the detailed information about the user.

现在应用程序已经有一个 bean 调用User它维护有关用户的详细信息。

public class User {

    private String id;
    private String firstName;
    private String lastName;

    ..
}

Note that this Useris not known to your JAXB Context. For simplicity we have User as POJO, but it can be any Valid Java Class.

请注意,User您的 JAXB 上下文不知道这一点。为简单起见,我们将 User 作为 POJO,但它可以是任何有效的 Java 类。

What application architect want is Event's performedByshould be represented as Userto gain full details.

应用程序架构师想要的是Event'sperformedBy应该被表示为User获得完整的细节。

Here is where @XmlJavaTypeAdapter comes into picture

这是@XmlJavaTypeAdapter 出现的地方

JAXBContext is aware about performedByas xs:string, but it has to be represented as Userin memory in Java.

JAXBContext 知道performedByas xs:string,但它必须User在 Java 中表示为 内存中。

Modified model looks like:

修改后的模型如下:

@XmlRootElement(name="event")
@XmlType(name="")
public class Event {

     @XmlElement(required=true)
     @XmlJavaTypeAdapter(UserAdapter.class) 
     protected User performedBy;
}

UserAdapter.java:

用户适配器.java:

public class UserAdapter extends XmlAdapter<String, User> {

     public String marshal(User boundType) throws   Exception {
             ..   
     } 

     public User unmarshal(String valueType) throws Exception {
             ..
     } 
}

The Adapter's definition says that -

适配器的定义说——

  1. BoundType is User (In Memeory representation)
  2. ValueType is String (The data type JAXB Context is aware of)
  1. BoundType 是用户(在内存表示中)
  2. ValueType 是 String(JAXB Context 知道的数据类型)

Coming to back to your question -

回到你的问题——

I find it somewhat redundant.

BTW, someMarshaller.setAdapter(...) seem not to do anything.

我觉得有些多余。

顺便说一句, someMarshaller.setAdapter(...) 似乎没有做任何事情。

Consider that our Adapter requires a class called UserContext in order to marshal / unmarshal sucessfully.

考虑到我们的 Adapter 需要一个名为 UserContext 的类才能成功编组/解组。

public class UserAdapter extends XmlAdapter<String, User> {

     private UserContext userContext;

     public String marshal(User boundType) throws   Exception {
          return boundType.getId();
     } 

     public User unmarshal(String valueType) throws Exception {
          return userContext.findUserById(valueType);
     } 
}

Now the question is how will UserAdapter will fetch an instace of UserContext ?? As a good design one should always supply it while it has got instantiated ..

现在的问题是 UserAdapter 将如何获取 UserContext 的实例?作为一个好的设计,应该总是在实例化时提供它。

public class UserAdapter extends XmlAdapter<String, User> {

     private UserContext userContext;

     public UserAdapter(UserContext userContext) {
        this.userContext = userContext;  
     } 

     public String marshal(User boundType) throws   Exception {
          return boundType.getId();
     } 

     public User unmarshal(String valueType) throws Exception {
          return userContext.findUserById(valueType);
     } 
}

But JAXB Runtime can only accept Adapter with No-args constructor .. (Obviously JAXBContext does not know about application specific model)

但是 JAXB Runtime 只能接受带有 No-args 构造函数的 Adapter ..(显然 JAXBContext 不知道特定于应用程序的模型)

So thankfully there is an option :D

谢天谢地,有一个选择:D

You can tell your unmarshallerto use given instance of UserAdapterrather than instating it by own its own.

您可以告诉您unmarshaller使用给定的实例,UserAdapter而不是通过自己的实例来安装它。

public class Test {

public static void main(String... args) { 
    JAXBContext context = JAXBContext.getInstance(Event.class);
    Unmarshaller unmarshaller = context.createUnmarshaller();

      UserContext userContext = null; // fetch it from some where
      unmarshaller.setAdapter(UserAdapter.class, new UserAdapter(userContext));

      Event event = (Event) unmarshaller.unmarshal(..);
   }
}

setAdaptermethod is available on both Marshaller& Unmarshaller

setAdapter方法可用于Marshaller&Unmarshaller

Note:

笔记:

  1. setAdapteron marshaller / unmarshaller does not mean that you don't have to use @XmlJavaTypeAdapter.

    @XmlRootElement(name="event")
    @XmlType(name="")
    public class Event {
    
        @XmlElement(required=true)
        // @XmlJavaTypeAdapter(UserAdapter.class) 
        protected User performedBy;
    }
    

    If you omit this JAXB runtime has no clue that User is your Bound Type & Value Type is something else. It will try to marshal Useras is & u will end up having wrong xml (or validation failure if enabled)

  2. While we have taken a scenario where Adapter is required to be with arguments, hence use setAdaptermethod.

    Some adavanced usages are also there, where in even if you have default no-arg constructor, yet you provide an instance of the Adapter

    May this adapter is configured with data, which marshal / unmarshal operation is using !

  1. setAdapter在 marshaller / unmarshaller 上并不意味着您不必使用@XmlJavaTypeAdapter.

    @XmlRootElement(name="event")
    @XmlType(name="")
    public class Event {
    
        @XmlElement(required=true)
        // @XmlJavaTypeAdapter(UserAdapter.class) 
        protected User performedBy;
    }
    

    如果您省略此 JAXB 运行时,则不知道 User 是您的绑定类型,而值类型是其他类型。它将尝试按User原样编组& 你最终会得到错误的 xml(或验证失败,如果启用)

  2. 虽然我们已经采取了一个场景,其中 Adapter 需要带参数,因此使用setAdapter方法。

    还有一些高级用法,即使你有默认的无参数构造函数,你也提供了一个 Adapter 的实例

    可能这个适配器配置了数据,编组/解组操作正在使用!

回答by JLM

You can use the package-info.java

您可以使用 package-info.java

That's called "package level".

这就是所谓的“包级别”。

Example : put a package-info.java in the same package that the class you want to marshall/unmarshall.

示例:将 package-info.java 放在要编组/解组的类的同一个包中。

Suppose you have a class mypackage.model.A and an adapter CalendarAdapter in mypackage.adapter. Declare a package-info.java file in mypackage.model containing :

假设您在 mypackage.adapter 中有一个类 mypackage.model.A 和一个适配器 CalendarAdapter。在 mypackage.model 中声明一个 package-info.java 文件,其中包含:

@XmlJavaTypeAdapters({
    @XmlJavaTypeAdapter(value = CalendarAdapter.class, type = Calendar.class)
})
package mypackage.model;

import java.util.Calendar;
import mypackage.adapter.CalendarAdapter;

All field of type Calendar in the class A will be marshalled or unmarshalled with the CalendarAdapter.

类 A 中所有类型为 Calendar 的字段都将使用 CalendarAdapter 进行编组或解组。

You can find useful informations there : http://blog.bdoughan.com/2012/02/jaxb-and-package-level-xmladapters.html

您可以在那里找到有用的信息:http: //blog.bdoughan.com/2012/02/jaxb-and-package-level-xmladapters.html