2011-07-28 33 views

Trả lời

18

Đây là một câu hỏi khá hay!

Câu trả lời ngắn gọn là không, sử dụng setAdapter trên marshaller/unmarshaller không có nghĩa là bạn không cần phải sử dụng @XmlJavaTypeAdapter.

Hãy để tôi giải thích điều này với một kịch bản giả định (nhưng hợp lệ!).

xem xét trong một ứng dụng web, người ta lấy về một sự kiện trong dạng xml có sau schema:

<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> 

Tương đương này, mô hình của bạn sẽ trông giống như:

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

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

Bây giờ ứng dụng đã có một bean được gọi là User, trong đó duy trì thông tin chi tiết về người dùng.

public class User { 

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

    .. 
} 

Lưu ý rằng điều này User không được biết đến trong ngữ cảnh JAXB của bạn. Để đơn giản, chúng tôi có User là POJO, nhưng nó có thể là bất kỳ Lớp Java hợp lệ nào.

Kiến trúc sư ứng dụng muốn là performedBy của phải được đại diện là User để có được chi tiết đầy đủ.

Đây là nơi @XmlJavaTypeAdapter đi vào hình ảnh

JAXBContext là nhận thức về performedBy như xs:string, nhưng nó phải được thể hiện dưới dạng User trong bộ nhớ trong Java.

mô hình Modified trông giống như:

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

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

UserAdapter.java:

public class UserAdapter extends XmlAdapter<String, User> { 

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

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

Các Adapter nói rằng -

  1. BoundType là User (Trong đại diện Memeory)
  2. ValueType là String (Bối cảnh kiểu dữ liệu JAXB được nhận thức)

Quay lại câu hỏi của bạn -

Tôi thấy nó hơi dư thừa.

BTW, someMarshaller.setAdapter (...) dường như không làm gì cả.

Hãy xem xét Bộ điều hợp của chúng tôi yêu cầu một lớp được gọi là UserContext để sắp xếp/unmarshal thành công.

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); 
    } 
} 

Bây giờ, câu hỏi là UserAdapter sẽ tìm nạp một instace của UserContext như thế nào ?? Là một thiết kế tốt ta nên luôn luôn cung cấp cho nó trong khi nó đã bị khởi ..

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); 
    } 
} 

Nhưng JAXB Runtime chỉ có thể chấp nhận Adapter với No-args constructor .. (Rõ ràng JAXBContext không biết về mô hình ứng dụng cụ thể)

vì vậy, may mắn có một tùy chọn: D

bạn có thể nói với bạn unmarshaller sử dụng Ví dụ nhất định UserAdapter hơn instating nó bằng cách riêng của mình.

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(..); 
    } 
} 

setAdapter phương pháp có sẵn trên cả Marshaller & Unmarshaller

Lưu ý:

  1. setAdapter trên marshaller/unmarshaller không có nghĩa là bạn không cần phải sử dụng @XmlJavaTypeAdapter.

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

    Nếu bạn bỏ qua thời gian chạy JAXB này không có đầu mối nào Người dùng là Loại ràng buộc & Loại giá trị của bạn là thứ khác. Nó sẽ cố gắng sắp xếp User như là & u sẽ kết thúc có sai xml (hoặc xác nhận thất bại nếu được kích hoạt)

  2. Trong khi chúng tôi đã thực hiện một kịch bản mà Adaptor bắt buộc phải có đối số, do đó sử dụng setAdapter phương pháp.

    Một số tập quán adavanced cũng có ở đó, nơi mà trong ngay cả khi bạn có mặc định không-arg constructor, nhưng bạn cung cấp một thể hiện của Adapter

    Có bộ chuyển đổi này được cấu hình với dữ liệu, mà soái/hoạt động unmarshal đang sử dụng !

+11

** câu trả lời quá ngắn là KHÔNG ** Bạn không thể sử dụng XmlAdapter mà không sử dụng @xmlJavaTypeAdapter chú thích. – user1128134

5

Bạn có thể sử dụng package-info.java

Đó được gọi là "mức khoán".

Ví dụ: đặt gói-info.java trong cùng một gói mà lớp bạn muốn marshall/unmarshall.

Giả sử bạn có lớp mypackage.model.A và bộ điều hợp CalendarAdapter trong mypackage.adapter. Khai báo một file package-info.java trong mypackage.model chứa:

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

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

Tất cả các lĩnh vực loại Lịch trong lớp A sẽ được marshalled hoặc unmarshalled với CalendarAdapter.

Bạn có thể tìm thấy thông tin hữu ích có: http://blog.bdoughan.com/2012/02/jaxb-and-package-level-xmladapters.html

Các vấn đề liên quan