#java #binding #pojo
Вопрос:
Мне нужен способ привязки объектов POJO к внешней сущности, которая может быть XML, YAML, структурированным текстом или чем-либо простым в написании и обслуживании, чтобы создавать макетные данные для модульного тестирования и TDD. Ниже приведены некоторые библиотеки, которые я пробовал, но основные проблемы с ними заключались в том, что я застрял (по крайней мере, более чем на 3 месяца) на Java 1.4. Я хотел бы получить представление о том, что я мог бы использовать вместо этого, с минимальными затратами и предварительной настройкой (например, с использованием схем или DTD, например), насколько это возможно, и без сложного XML. Вот библиотеки, которые мне действительно нравятся (но это, по — видимому, не работает с 1.4 или не поддерживает конструкторы-у вас должны быть установщики):
RE-JAXB (или Действительно простые привязки Java XML)
http://jvalentino.blogspot.com/2008/07/in-response-to-easiest-java-xml-binding.html
http://sourceforge.net/projects/rejaxb/
Seamlessy связывает это:
<item>
<title>Astronauts' Dirty Laundry</title>
<link>http://liftoff.msfc.nasa.gov/news/2003/news-laundry.asp</link>
<description>Compared to earlier spacecraft, the International Space
Station has many luxuries, but laundry facilities are not one of them.
Instead, astronauts have other options.</description>
<pubDate>Tue, 20 May 2003 08:56:02 GMT</pubDate>
<guid>http://liftoff.msfc.nasa.gov/2003/05/20.html#item570</guid>
</item>
К этому:
@ClassXmlNodeName("item")
public class Item {
private String title;
private String link;
private String description;
private String pubDate;
private String guid;
//getters and settings go here...
}
С помощью:
Rss rss = new Rss();
XmlBinderFactory.newInstance().bind(rss, new File("Rss2Test.xml"));
Проблема: Он полагается на аннотации, поэтому не подходит для Java 1.4
jYaml
http://jyaml.sourceforge.net/
Легко связывает это:
--- !user
name: Felipe Coury
password: felipe
modules:
- !module
id: 1
name: Main Menu
admin: !user
name: Admin
password: password
К этому:
public class User {
private String name;
private String password;
private List modules;
}
public class Module {
private int id;
private String name;
private User admin;
}
С помощью:
YamlReader reader = new YamlReader(new FileReader("example.yaml"));
reader.getConfig().setClassTag("user", User.class);
reader.getConfig().setClassTag("module", Module.class);
User user = (User) reader.read(User.class);
Проблема: Он не будет работать с конструкторами (поэтому не подходит для неизменяемых объектов). Мне пришлось бы либо изменить свои объекты, либо написать пользовательский код для обработки синтаксического анализа YAML.
Помните, что я хотел бы избегать — насколько это возможно — написания дескрипторов данных, я бы хотел, чтобы что-то «просто работало».
У вас есть какие-нибудь предложения?
Ответ №1:
Если объекты, подлежащие заполнению, являются простыми компонентами, может быть хорошей идеей взглянуть на класс BeanUtils apache common. Метод populate() может подходить для описанных случаев. Как правило, фреймворки для внедрения зависимостей, такие как Spring, могут быть очень полезны, но это может не решить текущую проблему. Для ввода в виде xml jibx может быть хорошей альтернативой, как и jaxb 1.0.
Комментарии:
1. Просто коротко посмотрел и насмешливо, и, кажется, все довольно просто, я посмотрю дальше. Спасибо за это сейчас.
Ответ №2:
Просто используйте XStream (для XML или вы можете попробовать использовать JSON).
Но…
Чувак, я просто не могу отделаться от мысли, что вывод тестовых данных за пределы самого модульного теста приведет тебя к нечитаемым тестам. Вам нужно будет просмотреть два файла при чтении тестового примера, вы потеряете инструменты рефакторинга (при изменении имени свойства). Джей Филдс может объяснить это лучше, чем я:
http://blog.jayfields.com/2007/06/testing-inline-setup.html
с уважением
Комментарии:
1. ИМЕННО это я и хочу сказать своей команде! Но они настояли. В настоящее время я делаю это, используя плавные интерфейсы, смешанные с шаблоном Builder, и (по крайней мере, мне это нравится)! 🙂
Ответ №3:
Вы можете попробовать использовать XMLEncoder/XMLDecoder по умолчанию, который был добавлен на платформу в Java1.4
Вот как я его использую.
import java.beans.XMLEncoder;
import java.beans.XMLDecoder;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class ToXml {
/**
* Write an object to a file in XML format.
* @param o - The object to serialize.
* @param file - The file where to write the object.
*/
public static void writeObject( Object o, String file ) {
XMLEncoder e = null;
try {
e = new XMLEncoder( new BufferedOutputStream( new FileOutputStream(file)));
e.writeObject(o);
}catch( IOException ioe ) {
throw new RuntimeException( ioe );
}finally{
if( e != null ) {
e.close();
}
}
}
/**
* Read a xml serialized object from the specified file.
* @param file - The file where the serialized xml version of the object is.
* @return The object represented by the xmlfile.
*/
public static Object readObject( String file ){
XMLDecoder d = null;
try {
d = new XMLDecoder( new BufferedInputStream( new FileInputStream(file)));
return d.readObject();
}catch( IOException ioe ) {
throw new RuntimeException( ioe );
}finally{
if( d != null ) {
d.close();
}
}
}
}
Это легко, просто, находится в основных библиотеках.
Вам просто нужно написать механизм загрузки.
У меня есть это приложение swing, которое загружает данные с удаленного EJB за 5-10 секунд. То, что я делаю, — это сохраняю предыдущую сессию в XML, как это, и когда приложение загружается, у него есть все данные из предыдущей сессии менее чем за 1 секунду.
Пока пользователь начинает работать с приложением, фоновый поток извлекает те элементы, которые изменились с момента последнего сеанса.