2013-04-17 35 views
8

Có cách nào để tạo trình chuyển đổi hoặc một số thao tác được thực hiện sau mỗi chuyển đổi không? Đối với ngữ cảnh, tôi cố gắng điền các giá trị mặc định cho các trường không có trong XML của tôi để duy trì khả năng tương thích ngược nếu mô hình dữ liệu của tôi thay đổi. Ví dụ, nếu tôi có đối tượng này:Đặt giá trị mặc định cho các trường không có trong XML trong XStream

class A { 
    private String b; 
    private String c; 
    private String d; 
} 

và XML của tôi là một cái gì đó như:

<a> 
<b>b</b> 
<d>d</d> 
</a> 

Tôi muốn nhập khẩu của tôi về XML để biết rằng có một giá trị mặc định cho trường c rằng là "c" và đặt nó trên A như vậy. Đây là một hoạt động chung mà tôi có thể thêm mặc định vào bất kỳ trường nào của biểu đồ rất phức tạp. Nếu có một số cách để kích hoạt một hàm sau mỗi lần chuyển đổi, nó có thể kiểm tra đối tượng hiện tại dựa vào một bản đồ các đối tượng mà tôi muốn đặt giá trị mặc định. Cũng cần lưu ý rằng việc sử dụng readResolve/readObject dường như không phải là một lựa chọn vì 1. readObject() dường như không làm việc cho tôi chút nào và 2. readResolve sẽ ghi đè lên trường bằng giá trị mặc định ngay cả khi nó thực sự là được bao gồm trong XML. Xin vui lòng cho tôi biết nếu giả định của tôi ở đây là sai mặc dù.

Sửa :: Tôi tìm thấy thread có liên quan này vào danh sách người dùng chỉ gửi thư: http://article.gmane.org/gmane.comp.java.xstream.user/4619/match=default+value

và nó có vẻ như là giải pháp gợi ý duy nhất là sử dụng readResolve() mà tôi đã nói không phải là một giải pháp hợp lệ.

Trả lời

1

Bạn sẽ cần một công cụ chuyển đổi.

Dưới đây là một ví dụ mã cho trường hợp của bạn:

public class AConverter implements Converter { 

    @Override 
public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { 
    A a = new A(); 
    String bValue = "b"; 
    String cValue = "c"; 
    String dValue = "d"; 

    while (reader.hasMoreChildren()) { 
     reader.moveDown(); 
     if ("b".equals(reader.getNodeName())) { 
      bValue = reader.getValue(); 
     } else if ("c".equals(reader.getNodeName())) { 
      cValue = reader.getValue(); 
     } else if ("d".equals(reader.getNodeName())) { 
      dValue = reader.getValue(); 
     } 
     reader.moveUp(); 
    } 
    a.setB(bValue); 
    a.setC(cValue); 
    a.setD(dValue); 

    return a; 
} 

@Override 
public void marshal(Object object, HierarchicalStreamWriter writer, MarshallingContext context) { 
    A a = (A) object; 
    writer.startNode("b"); 
    writer.setValue(a.getB()); 
    writer.endNode(); 
    writer.startNode("c"); 
    writer.setValue(a.getC()); 
    writer.endNode(); 
    writer.startNode("d"); 
    writer.setValue(a.getD()); 
    writer.endNode(); 


} 

@Override 
public boolean canConvert(Class clazz) { 
    return clazz == A.class; 
} 

}

Đừng quên đăng ký chuyển đổi:

XStream xs = new XStream(); 
xs.registerConverter(new AConverter()); 

EDIT: Cố định mã chuyển đổi.

+0

Cảm ơn pablosaraiva, nhưng điều này sẽ chỉ làm việc một cách rõ ràng cho một số lớp A. Tôi cần điều này để làm việc chung trên bất kỳ đối tượng nào trong đồ thị đầy đủ của tôi. Vì vậy, nó phải làm việc cho các đối tượng B/C/D, và bất kỳ đối tượng nào mà B C D cũng có thể có. Ngoài ra, nếu các trường bổ sung được thêm vào trong trường hợp này, nó sẽ yêu cầu duy trì công cụ chuyển đổi này. Lý tưởng nhất, tôi chỉ có thể nói một cái gì đó như newDefaultField (classWithNewDefault.class, newFieldName, newDefaultValue) bất cứ lúc nào tôi cần phải thêm một mặc định mới. – eipark

+0

Đây chỉ là một giải pháp đồ chơi cho vấn đề đồ chơi. Có thể bạn sẽ cần một trình biến đổi cho mọi lớp với các giá trị mặc định. Bạn không cần phải xây dựng các đối tượng bằng tay tại unmarshal, bạn có thể có một nhà máy để chăm sóc nó. Tôi hy vọng nó sẽ giúp. – pablosaraiva

+0

Phải. Tôi đoán mục đích là để tránh bất kỳ bảo trì thực sự mà có thể nhận được phức tạp và ra khỏi bàn tay một cách nhanh chóng. Thật không may tôi không nghĩ rằng XStream cung cấp một giải pháp tốt hơn cho điều này vượt ra ngoài chuyển đổi cho mỗi, hoặc một readResolve() ở khắp mọi nơi. – eipark

1

c sẽ được đặt thành null khi XML không có bất kỳ giá trị nào được đặt cho c. Sau đó, bạn có thể kiểm tra null trong bộ nạp của mình và trả lại giá trị mặc định thích hợp.

7

Sử dụng PureJavaReflectionProvider

XStream xstream = new XStream(new PureJavaReflectionProvider()); 

và chỉ cần khởi tạo đối tượng của bạn với các giá trị mặc định như bình thường. Hoặc thông qua khởi tạo trường hoặc mã hàm tạo.

nền

Nếu bạn không chỉ định một XStream ReflectionProvider cố gắng tìm nhà cung cấp phản ánh tốt nhất. Nhưng tốt nhất ReflectionProvider cho xstream có thể không phải là tốt nhất cho bạn, bởi vì nó thường chọn Sun14ReflectionProvider.

Sun14ReflectionProvider sử dụng cùng một chiến lược instantiation như cơ chế tuần tự hóa java và điều đó có nghĩa là nó bỏ qua mã trình xây dựng hoặc để được chi tiết hơn - mã khởi tạo đối tượng.

Do đó khởi tạo instance field như

class A { 
    private String b = "DEFAULT"; 
} 

sẽ không được áp dụng và cũng đang xây dựng sẽ không được áp dụng, ví dụ

class A { 
    private String b; 

    public A(){ 
     b = "DEFAULT"; 
    } 
} 

Thay vì sử dụng (như tên ngụ ý) API phản chiếu java để tạo đối tượng nhanh, ví dụ: Class.newInstance() và do đó mã khởi tạo đối tượng được thực thi.

+0

Cách tiếp cận này không hoạt động. Ngay cả PureJavaReflectionProvider đặt giá trị mặc định là null –

+0

điều này dường như không hoạt động với Scala, nơi một lớp có một hàm tạo giá trị mặc định, tức là lớp A (String b = "") – sowen

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