Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Java: Общие вопросы > Биндинг XML/beans


Автор: Maksym 6.9.2006, 14:20
Необходимо превращать сложные вложенные бины (в том числе с листами и хэшмапами) в xml -- а затем из xml получать экземпляры соответсвующих бинов. Желательна возможность мапинга (класс -- xml шаблон) в отдельных конфигурационных файлах.
В обещем и целом пока что в колебаниях между http://www.castor.org/ и http://xmlbeans.apache.org/.
У кого есть какие соображения, опыт, что посоветуете?

Автор: LSD 6.9.2006, 14:38
Я юзаю XML-Beans. Маппинг в отдельном файле у него есть, но вот возможности сложного маппинга, особенно всяких Map-ов, не уверен. Я пользуюсь тем классами, что он мне нагенерировал по схеме. В плюсы могу отметить хорошую скорость, даже быстрее чем JAXB.

Автор: powerOn 6.9.2006, 16:20
ИМХО, JAXB весьма неплох: он позволяет по XML Schema (xsd) сгенерировать java классы. При этом Sun гарантирует 100 % поддержку XML схем. Так же можно  выполнить и обратную операцию, т.е. java класс -> XML Schema. На счет скорости работы - с другими не сравнивал, не знаю.

Автор: Maksym 7.9.2006, 17:25
LSD
Что-то никак не могу разобраться как из объекта в процессе работы программы получить его xml представление... можно, плз, кусочек кода или пример  smile 

MoonCat
Если можно аналогичный кусочек (java класс -> XML Schema) для JAXB, буду очень признателен  smile 

Автор: LSD 7.9.2006, 17:33
Вот мой тест которым я проверял это дело на скорость. Там есть как генерация XML из объектов, так и парсинг XML в объекты.
Код
import java.io.*;
import java.util.Calendar;
import java.util.Random;

import org.apache.xmlbeans.XmlException;
import org.apache.xmlbeans.XmlOptions;

public class Main
{
  public static final int TEST_RUN_COUNT = 50;
  public static final int RUN_COUNT = 100;
  public static final int ENTRY_COUNT = 1;

  private static Random random = new Random();

  public static void main(String[] args) throws Exception
  {
    RootDTOPlusDocument doc = generateDocument();

    validateDocument(doc);

    ////////////////////////////////////////////////
    //init save options
    XmlOptions xmlOptions = new XmlOptions();
    xmlOptions.setCharacterEncoding("UTF-8");
    xmlOptions.setSavePrettyPrint();
    xmlOptions.setSavePrettyPrintIndent(2);
    ByteArrayOutputStream byteOut = new ByteArrayOutputStream(1024);

    saveToDevNull(doc, xmlOptions);

    saveToByteArray(byteOut, doc, xmlOptions);

    ////////////////////////////////////////////////
    //init parse options
    byteOut.reset();
    doc.save(byteOut, xmlOptions);
    ByteArrayInputStream byteIn = new ByteArrayInputStream(byteOut.toByteArray());

    parseAndValidate(byteIn);

    //harm data
    doc.getRootDTOPlus().getHumanArray(0).setTransactId(new byte[0]);
    byteOut.reset();
    doc.save(byteOut, xmlOptions);
    byteIn = new ByteArrayInputStream(byteOut.toByteArray());

    parseValidating(byteIn);
  }

  private static void parseValidating(ByteArrayInputStream byteIn) throws XmlException, IOException
  {
    XmlOptions xmlOptions;
    long time;
    xmlOptions = new XmlOptions();
    xmlOptions.setValidateOnSet();

    time = System.currentTimeMillis();
    byteIn.reset();
    RootDTOPlusDocument.Factory.parse(byteIn, xmlOptions);
    time = System.currentTimeMillis() - time;
    System.out.println("XML first parse vaidating from ByteArrayInputStream time = " + time + " ms");

    for(int i = 0; i < TEST_RUN_COUNT; i++)
    {
      byteIn.reset();
      RootDTOPlusDocument.Factory.parse(byteIn, xmlOptions);
    }

    time = System.currentTimeMillis();
    for(int i = 0; i < RUN_COUNT; i++)
    {
      byteIn.reset();
      RootDTOPlusDocument.Factory.parse(byteIn, xmlOptions);
    }
    time = System.currentTimeMillis() - time;
    System.out.println("XML parse vaidating from ByteArrayInputStream time = " + ((double) time) / RUN_COUNT + " ms");
  }

  private static void parseAndValidate(ByteArrayInputStream byteIn) throws XmlException, IOException
  {
    long time;
    RootDTOPlusDocument doc;
    time = System.currentTimeMillis();
    byteIn.reset();
    doc = RootDTOPlusDocument.Factory.parse(byteIn);
    doc.validate();
    time = System.currentTimeMillis() - time;
    System.out.println("XML first parse and validate from ByteArrayInputStream time = " + time + " ms");

    for(int i = 0; i < TEST_RUN_COUNT; i++)
    {
      byteIn.reset();
      doc = RootDTOPlusDocument.Factory.parse(byteIn);
      doc.validate();
    }

    time = System.currentTimeMillis();
    for(int i = 0; i < RUN_COUNT; i++)
    {
      byteIn.reset();
      doc = RootDTOPlusDocument.Factory.parse(byteIn);
      doc.validate();
    }
    time = System.currentTimeMillis() - time;
    System.out.println("XML parse and validate from ByteArrayInputStream time = " + ((double) time) / RUN_COUNT + " ms");
  }

  private static void saveToByteArray(ByteArrayOutputStream byteOut, RootDTOPlusDocument doc, XmlOptions xmlOptions) throws IOException
  {
    long time;
    time = System.currentTimeMillis();
    byteOut.reset();
    doc.save(byteOut, xmlOptions);
    time = System.currentTimeMillis() - time;
    System.out.println("XML first write to ByteArrayOutputStream time = " + time + " ms");


    for(int i = 0; i < TEST_RUN_COUNT; i++)
    {
      byteOut.reset();
      doc.save(byteOut, xmlOptions);
    }

    time = System.currentTimeMillis();
    for(int i = 0; i < RUN_COUNT; i++)
    {
      byteOut.reset();
      doc.save(byteOut, xmlOptions);
    }
    time = System.currentTimeMillis() - time;
    System.out.println("XML write to ByteArrayOutputStream time = " + ((double) time) / RUN_COUNT + " ms");
  }

  private static void saveToDevNull(RootDTOPlusDocument doc, XmlOptions xmlOptions) throws IOException
  {
    DevNull devNull = new DevNull();
    long time;
    time = System.currentTimeMillis();
    doc.save(devNull, xmlOptions);
    time = System.currentTimeMillis() - time;
    System.out.println("XML first write to /dev/null time = " + time + " ms");


    for(int i = 0; i < TEST_RUN_COUNT; i++)
      doc.save(devNull, xmlOptions);

    time = System.currentTimeMillis();
    for(int i = 0; i < RUN_COUNT; i++)
      doc.save(devNull, xmlOptions);
    time = System.currentTimeMillis() - time;
    System.out.println("XML write to /dev/null time = " + ((double) time) / RUN_COUNT + " ms");
  }

  private static void validateDocument(RootDTOPlusDocument doc)
  {
    long time = System.currentTimeMillis();
    doc.validate();
    time = System.currentTimeMillis() - time;
    System.out.println("Validate first time = " + time + " ms");

    for(int i = 0; i < TEST_RUN_COUNT; i++)
      doc.validate();

    time = System.currentTimeMillis();
    for(int i = 0; i < RUN_COUNT; i++)
      doc.validate();
    time = System.currentTimeMillis() - time;
    System.out.println("Validate time = " + ((double) time) / RUN_COUNT + " ms");
  }

  private static RootDTOPlusDocument generateDocument()
  {
    RootDTOPlusDocument doc = RootDTOPlusDocument.Factory.newInstance();
    RootDTOPlusDocument.RootDTOPlus root = doc.addNewRootDTOPlus();
    for(int i = 0; i < ENTRY_COUNT; i++)
      generateHuman(root);
    return doc;
  }

  private static void generateHuman(RootDTOPlusDocument.RootDTOPlus root)
  {
    HumanType human = root.addNewHuman();
    human.setTransactId(getGUID());
    human.setDml(DmlType.INSERT);
    human.addNewAdressing().setGuid(getGUID());
    HumanFieldsType humanFields = human.addNewFields();
    humanFields.setFirstName("Акакий");
    humanFields.setMiddleName("Назарыч");
    humanFields.setLastName("Зербенштейн");
    humanFields.setSex((short) 0);
    humanFields.setDateReg(Calendar.getInstance());
    humanFields.setComment("Аффтар ЖЖОТ! Каменты рулят! Пеши исчо!");
    LinkType link = human.addNewLinks();
    link.setDtoName("HUMAN");
    link.setRole("parent");
    link.setGuid(getGUID());
  }

  private static byte[] getGUID()
  {
    byte[] guid = new byte[16];
    random.nextBytes(guid);
    return guid;
  }

  private static class DevNull extends OutputStream
  {
    public DevNull()
    {
    }

    public void write(byte b[])
    {
    }

    public void write(byte b[], int off, int len)
    {
    }

    public void flush()
    {
    }

    public void close()
    {
    }

    public void write(int b)
    {
    }
  }
}

Автор: powerOn 7.9.2006, 17:40
Вот есть у нас схема:

Код

<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.ibm.com" xmlns:booklist="http://www.ibm.com">
    <element name="bookstore" type="booklist:booklist"></element>
    
    <complexType name="bookType">
        <sequence>
            <element name="title" type="string"></element>
            <element name="author" type="string"></element>
            <element name="year" type="gYear"></element>
        </sequence>
    </complexType>
    
    <complexType name="booklist">
        <sequence>
            <element name="book" type="booklist:bookType" minOccurs="1" maxOccurs="unbounded"></element>
        </sequence>
    </complexType>
    
</schema>


Компилим её с помощью xjc:
Цитата

C:\Sun\jwsdp-2.0\jaxb\bin>xjc TestSchema.xsd
parsing a schema...
compiling a schema...
com\ibm\BookType.java
com\ibm\Booklist.java
com\ibm\ObjectFactory.java
com\ibm\package-info.java

C:\Sun\jwsdp-2.0\jaxb\bin>


полученные классы кидаем в проект вместе с JAXB библиотеками.

Потом пишем тестовый код:
Код

import com.ibm.BookType;
import com.ibm.Booklist;
import com.ibm.ObjectFactory;
import com.sun.org.apache.xerces.internal.jaxp.datatype.XMLGregorianCalendarImpl;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.GregorianCalendar;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;

/**
 *
 * @author tyurikov
 */
public class NewClass {
    
    /** Creates a new instance of NewClass */
    public NewClass() {
    }
    
    public static void main(String[] args) {
        
        try {            
            ObjectFactory of = new ObjectFactory();
            Booklist booklist = of.createBooklist();
            BookType book = of.createBookType();
            
            book.setAuthor("Test Author");
            book.setTitle("Test Title");
            book.setYear(new XMLGregorianCalendarImpl(new GregorianCalendar(2006, 1, 1)));
            booklist.getBook().add(book);
            
            JAXBElement jbElem = of.createBookstore(booklist);
            JAXBContext jaxbContent = JAXBContext.newInstance("com.ibm");
            // Для записи.
            Marshaller u = jaxbContent.createMarshaller();
            FileOutputStream fos = new FileOutputStream("TestXML.xml");
            u.marshal(jbElem, fos);
            fos.flush();
            fos.close();
            
            // Для чтения.
            Unmarshaller um = jaxbContent.createUnmarshaller();
            javax.xml.bind.JAXBElement o = (javax.xml.bind.JAXBElement) um.unmarshal(new FileInputStream("BookList.xml"));
            Booklist bll = (Booklist) o.getValue();
            System.out.println(bll.getBook().get(0).getAuthor());
            
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
    
}


Надеюсь код будет понятен.

Автор: batigoal 8.9.2006, 09:54
MoonCat, а в сгенерированные классы можно вносить изменения?

Автор: Maksym 8.9.2006, 09:58
MoonCat
Мммм, а что есть по сути своей ObjectFactory? Правильно ли я понял что сериализация bean -> xml возможно только для сгенерированных классов? И свой корректно написанный бин -- не сериализируеш...?

Автор: powerOn 8.9.2006, 11:11
Цитата(Lamer George @  8.9.2006,  09:54 Найти цитируемый пост)
MoonCat, а в сгенерированные классы можно вносить изменения? 

Можно. Главное ничего не поломать. 
У JAXB есть некоторая методика по которой она может работать с XML. Если её соблюдать, то все должно быть в порядке. Хоть руками код пиши, лишь бы требованиям JAXB удовлетворяло. XCJ в данном случае позволяет избавитьтся от нудной процедуры самостоятельного написания необходимых классов и автоматически генерирует код. 

Цитата(Maksym @  8.9.2006,  09:58 Найти цитируемый пост)
Мммм, а что есть по сути своей ObjectFactory? Правильно ли я понял что сериализация bean -> xml возможно только для сгенерированных классов? И свой корректно написанный бин -- не сериализируеш...? 


JAXB это механизм который позволяет работать с XML документами так же, как если бы это были простые классы. Собственно XCJ этим и занимается - генерирует классы-отображения XML.  ObjectFatory представляет собой фабрику классов для различных узлов XML документа. Например, если Вы захотите создать новый XML документ, то можно с помощью ObjectFactory получить необходимые узлы и сформировать из них конкретный документ:

Код

            // Формирует документ.
            ObjectFactory of = new ObjectFactory();
            Booklist booklist = of.createBooklist();
            BookType book = of.createBookType();
            
            book.setAuthor("Test Author");
            book.setTitle("Test Title");
            book.setYear(new XMLGregorianCalendarImpl(new GregorianCalendar(2006, 1, 1)));
            booklist.getBook().add(book);
            
            JAXBElement jbElem = of.createBookstore(booklist);
                       
            // Записсываем документ в файл.
            JAXBContext jaxbContent = JAXBContext.newInstance("com.ibm");
            Marshaller u = jaxbContent.createMarshaller();
            FileOutputStream fos = new FileOutputStream("TestXML.xml");
            u.marshal(jbElem, fos);
            fos.flush();
            fos.close();


Автор: Maksym 8.9.2006, 17:06
MoonCat
Понятно, большое спасибо. Но пока остановился на Castor.

Автор: Tony 9.9.2006, 22:41
посмотри XMLEncoder и  XMLDecoder iz jdk

Автор: Nobody 10.9.2006, 16:53
Tony, +1

Автор: Maksym 11.9.2006, 10:43
Tony
 smile Разве их xml можно конфигурировать с помощью мапинга?
Возможно я ошибаюсь, но они дают xml в котором теги стого соответствуют именам методов бина.

Автор: Tony 11.9.2006, 15:20
Цитата(Maksym @ 11.9.2006,  10:43)
Tony
 smile Разве их xml можно конфигурировать с помощью мапинга?
Возможно я ошибаюсь, но они дают xml в котором теги стого соответствуют именам методов бина.

не понал.XMLEncoder просто генерит хмл по методам обэкта.Всё.Это 4то тебе надо.Просто и со вкусом :]

Автор: LSD 11.9.2006, 17:43
Цитата(Tony @  11.9.2006,  16:20 Найти цитируемый пост)
не понал.XMLEncoder просто генерит хмл по методам обэкта.Всё.Это 4то тебе надо.Просто и со вкусом :]

Ему надо, чтобы XML имел определенный формат. Например XML Schema может быть заранее задана, как часть протокола обмена.

Автор: Maksym 11.9.2006, 18:42
LSD
Да, xsd описаны заранее. Описывают формты сообщений, которыми стендэлон приложения обмениваются через сокеты. Чуть позже надстроим это Web Service'ами, а пока что так... Castor пока справляется, он даже на базу данных может мапится оказывается по принципу Hibernate (кажется Castor был раньше), по сравнительной производительности этого дела пока что не скажу ниче...

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)