Вопрос по pojo, jaxb, java – Создание неизменяемых объектов с использованием JAXB

13

Я использую JAXB для создания объектов Java из файла XSD. Я создаю неизменяемые оболочки, чтобы скрыть объекты, сгенерированные JAXB (ранее я обновлял объекты JAXB для реализации неизменяемого интерфейса и возврата интерфейса клиенту. Но понял, что менять автоматически сгенерированные классы плохо, следовательно, используя оболочки)

В настоящее время я возвращаю эти неизменные оболочки в клиентское приложение. Есть ли какая-либо опция, чтобы автоматически сгенерированные классы были неизменяемыми, и это позволит избежать дополнительной работы по созданию неизменяемых оболочек. Любой другой подход приветствуется.

Thanks

Ваш Ответ

5   ответов
-2

м их клиенту. Тебе понадобитсяJavassist создавать прокси из классов (создавать прокси из интерфейсов можно напрямую с помощью Java SE).

Затем вы можете выдать исключение, если методы начинаются с & quot; set & quot; вызваны.

Вот класс многократного использования с методом, который может обернуть "любой" 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;
 }
}

А вот пример кода. Позвольте Сотруднику быть вашим бобом:

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

И вот тестовый пример, показывающий, что вы можете создать прокси для POJO, использовать его геттеры, но вы не можете использовать его сеттеры

@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());
    }
}
Это худшая идея, которую человечество когда-либо задумывало. Как именно это будет кому-нибудь полезно? Кто хочет классы, которые неожиданно генерируют исключения во время выполнения? Первоначальный плакат хотел создать неизменные классы по дизайну, а не по FUD.
Я с тобой согласен. Скрытие сеттеров статически было бы лучшим решением. Мое решение пытается создать оболочки без изменения сгенерированных компонентов и без необходимости писать больше кода. Кроме того, вы могли увидеть такую плохую идею в Стандартном Java API:docs.oracle.com/javase/6/docs/api/java/util/…или в API Коллекций Google:google-collections.googlecode.com/svn/trunk/javadoc/com/google/…, E) Оба из этих исключений во время выполнения.
9
Это правильный ответ на вопрос, не уверен, почему другие проголосовали выше
1

http://blog.bdoughan.com/2010/12/jaxb-and-immutable-objects.html Blaise Doughan (который много знает о JAXB), похоже, что нет встроенной поддержки неизменяемых объектов, поэтому ваши объекты-обертки необходимы.

@AlessandroSantini Справедливая точка зрения. Будем надеяться, что в будущем выпуске это будет немного меньше усилий.
Я возражал против вашего заявления "нет никакой встроенной поддержки неизменяемых объектов" и не факт, что усилия эквивалентны :)
Конечно - но эти три класса требуют столько же усилий, сколько и просто написание оберток.
Это на самом деле говорит о том, что вам нужен адаптер (это конструкция JAXB). Да, вам нужно создать три класса (неизменяемый, изменяемый и адаптер), но все же вы можете сделать это.
2

поэтому единственно возможным подходом было бы защитить конструктор без аргументов и сеттеры, заканчивая & quot; псевдо-неизменяемыми & quot; объекты.

Я выбираю этот подход каждый раз, когда пишу вручную JAXB-аннотированные классы, но вы можете проверить, возможно ли это и для сгенерированного кода.

27

ние для установки неинициализированных конечных переменных. так что вы можете инициализировать null в приватном конструкторе и использовать JAXB + неизменным без каких-либо XMLAdapter.

пример изhttps://test.kuali.org/svn/rice/sandbox/immutable-jaxb/ , получил это из комментария в блоге Блеза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;
    }

}
Это должно быть помечено как лучший ответ, это экономит нам на написании класса адаптера и сопоставленного класса для каждого неизменяемого объекта, очень легкого решения. Спасибо!

Похожие вопросы