2012-06-14 14 views
12

Tôi đang sử dụng JAXB để tạo các đối tượng Java từ tệp XSD. Tôi đang tạo các trình bao bọc bất biến để che giấu các đối tượng được tạo bởi JAXB (trước đó tôi đã cập nhật các đối tượng JAXB để triển khai giao diện bất biến và giao diện trả về cho máy khách. Nhưng đã nhận ra rằng việc thay đổi các lớp được tạo tự động là không tốt, do đó sử dụng hàm bao)Tạo các đối tượng không thay đổi bằng cách sử dụngJAXB

Hiện tại tôi đang trả lại các trình bao bọc bất biến này cho ứng dụng khách. Có bất kỳ tùy chọn nào để các lớp được tạo tự động sẽ không thay đổi được và nó sẽ tránh làm việc thêm trong việc tạo ra các trình bao bọc không thay đổi được. Bất kỳ cách tiếp cận nào khác đều được khuyến khích.

  • Cảm ơn

Trả lời

-2

Bạn có thể tạo một Proxy cho đậu của bạn ngay trước khi trả lại cho khách hàng. Bạn sẽ cần javassist để tạo Proxy từ các lớp (tạo proxy từ giao diện có thể được thực hiện trực tiếp với Java SE).

Sau đó, bạn có thể ném ngoại lệ nếu phương thức bắt đầu bằng "set" được gọi.

Dưới đây là một lớp học thể tái sử dụng với một phương pháp có thể quấn "bất kỳ" POJO:

import java.lang.reflect.Method; 

import javassist.util.proxy.MethodFilter; 
import javassist.util.proxy.MethodHandler; 
import javassist.util.proxy.Proxy; 
import javassist.util.proxy.ProxyFactory; 

public class Utils { 

public static <C> C createInmutableBean(Class<C> clazz, final C instance) 
     throws InstantiationException, IllegalAccessException { 
    if (!clazz.isAssignableFrom(instance.getClass())) { 
     throw new IllegalArgumentException("given instance of class " 
       + instance.getClass() + " is not a subclass of " + clazz); 
    } 
    ProxyFactory f = new ProxyFactory(); 
    f.setSuperclass(clazz); 
    f.setFilter(new MethodFilter() { 
     public boolean isHandled(Method m) { 
      // ignore finalize() 
      return !m.getName().equals("finalize"); 
     } 
    }); 
    Class c = f.createClass(); 
    MethodHandler mi = new MethodHandler() { 
     public Object invoke(Object self, Method m, Method proceed, 
       Object[] args) throws Throwable { 
      if (m.getName().startsWith("set")) { 
       throw new RuntimeException("this bean is inmutable!"); 
      } 

      return m.invoke(instance, args); // execute the original method 
               // over the instance 
     } 
    }; 
    C proxy = (C) c.newInstance(); 

    ((Proxy) proxy).setHandler(mi); 
    return (C) proxy; 
} 
} 

Và đây là một ví dụ mã. Hãy để nhân viên được đậu của bạn:

public class Employee{ 
    private String name="John"; 
    private String surname="Smith"; 
    public String getName() { 
    return name; 
    } 
    public void setName(String name) { 
    this.name = name; 
    } 
    public String getSurname() { 
    return surname; 
    } 
    public void setSurname(String surname) { 
    this.surname = surname; 
    } 
}; 

Và đây là một trường hợp thử nghiệm cho thấy rằng bạn có thể tạo một proxy cho một POJO, sử dụng thu khí của nó, nhưng bạn không thể sử dụng setters nó

@Test 
public void testProxy() throws InstantiationException, IllegalAccessException{ 
    Employee aBean = new Employee(); 

    //I can modify the bean 
    aBean.setName("Obi-Wan"); 
    aBean.setSurname("Kenobi"); 

    //create the protected java bean with the generic utility 
    Employee protectedBean = Utils.createInmutableBean(Employee.class, aBean); 

    //I can read 
    System.out.println("Name: "+protectedBean.getName()); 
    System.out.println("Name: "+protectedBean.getSurname()); 

    //but I can't modify 
    try{ 
     protectedBean.setName("Luke"); 
     protectedBean.setSurname("Skywalker"); 
     throw new RuntimeException("The test should not have reached this line!"); 
    }catch(Exception e){ 
     //I should be here 
     System.out.println("The exception was expected! The bean should not be modified (exception message: "+e.getMessage()+")"); 
     assertEquals("Obi-Wan", protectedBean.getName()); 
     assertEquals("Kenobi", protectedBean.getSurname()); 
    } 
} 
+4

Đây là ý tưởng tồi tệ nhất mà nhân loại đã từng hình thành. Làm thế nào chính xác là điều này sẽ có lợi cho bất cứ ai? Ai muốn các lớp học bất ngờ ném ngoại lệ thời gian chạy? Những gì các poster ban đầu muốn được các lớp học bất biến theo thiết kế, không phải bởi FUD. –

+0

Tôi đồng ý với bạn. Ẩn các setters tĩnh sẽ là một giải pháp tốt hơn. Giải pháp của tôi cố gắng tạo trình bao bọc mà không thay đổi các bean được tạo ra và không cần phải viết thêm mã. Ngoài ra, bạn có thể đã thấy ý tưởng tồi trong API Java chuẩn: http://docs.oracle.com/javase/6/docs/api/java/util/Collections.html#unmodifiableList(java.util. Danh sách) hoặc trong API Bộ sưu tập của Google: https://google-collections.googlecode.com/svn/trunk/javadoc/com/google/common/collect/ImmutableList.html#set(int, E) Cả hai ném ngoại lệ thời gian chạy. – lipido

1

Dựa trên bài viết trên blog này http://blog.bdoughan.com/2010/12/jaxb-and-immutable-objects.html bởi Blaise Doughan (người hiểu biết rất nhiều về JAXB), có vẻ như không có hỗ trợ cho các đối tượng bất biến, vì vậy đối tượng bao bọc của bạn là cần thiết.

+0

Nó thực sự nói rằng bạn cần một bộ chuyển đổi (đó là một cấu trúc JAXB). Có, bạn cần phải tạo ba lớp (không thay đổi, có thể thay đổi và bộ chuyển đổi) nhưng bạn vẫn có thể thực hiện điều đó. –

+0

Chắc chắn - nhưng ba lớp đó có cùng số lượng công sức như chỉ viết trình bao bọc. – artbristol

+0

Tôi đã phản đối tuyên bố của bạn "không có hỗ trợ gốc cho các đối tượng bất biến" và không thực tế là nỗ lực tương đương :) –

2

JAXB có thể làm việc với các nhà xây dựng/phương pháp ngoài công lập, vì vậy cách tiếp cận khả thi duy nhất là bảo vệ bộ tạo và định vị no-arg, kết thúc bằng các đối tượng "giả không thay đổi".

Tôi chọn phương pháp này mỗi khi tôi viết các lớp được chú thích JAXB theo cách thủ công, nhưng bạn có thể kiểm tra xem điều này có khả thi cho mã được tạo hay không.

23

tính từ JSR-133 (phụ thuộc Java 1.5), bạn có thể sử dụng phản chiếu để đặt biến cuối cùng chưa được khởi tạo. vì vậy bạn có thể init thành null trong hàm tạo riêng và sử dụng JAXB + không thay đổi một cách rõ ràng mà không cần bất kỳ XMLAdapter nào.

ví dụ từ https://test.kuali.org/svn/rice/sandbox/immutable-jaxb/, nhận này từ một bình luận trên blog của Blaise http://blog.bdoughan.com/2010/12/jaxb-and-immutable-objects.html#comment-form_584069422380571931

package blog.immutable; 

import javax.xml.bind.annotation.XmlAccessType; 
import javax.xml.bind.annotation.XmlAccessorType; 
import javax.xml.bind.annotation.XmlAttribute; 
import javax.xml.bind.annotation.XmlElement; 
import javax.xml.bind.annotation.XmlRootElement; 

@XmlRootElement(name="customer") 
@XmlAccessorType(XmlAccessType.NONE) 
public final class Customer { 

    @XmlAttribute 
    private final String name; 

    @XmlElement 
    private final Address address; 

    @SuppressWarnings("unused") 
    private Customer() { 
     this(null, null); 
    } 

    public Customer(String name, Address address) { 
     this.name = name; 
     this.address = address; 
    } 

    public String getName() { 
     return name; 
    } 

    public Address getAddress() { 
     return address; 
    } 

} 
+0

Điều này sẽ được đánh dấu là câu trả lời tốt nhất, nó giúp chúng ta viết một lớp bộ điều hợp và một lớp ánh xạ cho mỗi đối tượng bất biến, một giải pháp rất nhẹ. Cảm ơn bạn! –

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