Java - HyperJaxb - From Xml (Jaxb) to database (Jpa)

About

HyperJaxb is a Jaxb plugin that creates classes that are:

  • JAXB-enabled (thanks to the JAXB schema compiler)
  • and JPA-enabled (thanks to the Hyperjaxb3 Jaxb plugin)

HyperJaxb permits then to have Jaxb + Jpa in one API.

JAXB vs. JPA - JAXB is not 100% compatible with JPA

Hyperjaxb3 is a code generator. It provides a JAXB 2 plugin which participates in JAXB's code generation - and produces all necessary JPA annotations as well as the supporting code to make the class JAXB and JPA compatible.

Prerequisites

Data

From the XML Schema Primer, download the purchase order schema example:

Project Structure

Download the basic project templates for Ant (hyperjaxb3-ejb-template-basic-0.5.6-ant-src.zip)

Steps

Directory Structure

  • Unpack the basic project templates and import it into an Eclipse Java project
  • Add the content of the lib directory in your class path
  • Put your schema (*.xsd) and binding files (*.xjb) into src/main/resources.
  • Put your XML samples (*.xml) into src/test/samples.

Run the build

  • Run mvn clean install for Maven or ant clean install for Ant.
ant clean install
Buildfile: D:\workspace\HyperJaxb2\build.xml

clean:

generate-sources:
    [mkdir] Created dir: D:\workspace\HyperJaxb2\target\generated-sources\xjc
      [xjc] Consider using <depends>/<produces> so that XJC won't do unnecessary compilation
      [xjc] Compiling file:/D:/workspace/HyperJaxb2/src/main/resources/po.xsd
      [xjc] Writing output to D:\workspace\HyperJaxb2\target\generated-sources\xjc

compile:
    [mkdir] Created dir: D:\workspace\HyperJaxb2\target\classes
    [javac] D:\workspace\HyperJaxb2\build.xml:142: warning: 'includeantruntime' was not set, default
ing to build.sysclasspath=last; set to false for repeatable builds
    [javac] Compiling 5 source files to D:\workspace\HyperJaxb2\target\classes
     [copy] Copying 3 files to D:\workspace\HyperJaxb2\target\classes

test-compile:
    [mkdir] Created dir: D:\workspace\HyperJaxb2\target\test-classes
    [javac] D:\workspace\HyperJaxb2\build.xml:158: warning: 'includeantruntime' was not set, default
ing to build.sysclasspath=last; set to false for repeatable builds
    [javac] Compiling 5 source files to D:\workspace\HyperJaxb2\target\test-classes
     [copy] Copying 3 files to D:\workspace\HyperJaxb2\target\test-classes

test:
    [mkdir] Created dir: D:\workspace\HyperJaxb2\target\junit-reports
    [junit] Running RoundtripTest
    [junit] Tests run: 1, Failures: 0, Errors: 0, Time elapsed: 1.372 sec

package:
      [jar] Building jar: D:\workspace\HyperJaxb2\target\hyperjaxb3-ejb-template-basic-ant-0.5.6.jar


install:

BUILD SUCCESSFUL
Total time: 9 seconds

Check generated content

We got produced from the XJC schema compiler and Hyperjaxb3 plugin:

  • a set of Java files containing both JAXB and JPA annotations.

The class contains @Entity, @Table, @ManyToOne and few other annotations generated by the Hyperjaxb3 plugin. These annotations turn this class into an entity which can be persisted with JPA.

Persistence.xml:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<persistence version="1.0" 
    xsi:schemaLocation="http://java.sun.com/xml/ns/persistence 
                        http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd
                        http://java.sun.com/xml/ns/persistence/orm
                        http://java.sun.com/xml/ns/persistence/orm_1_0.xsd" 
    xmlns="http://java.sun.com/xml/ns/persistence" 
    xmlns:orm="http://java.sun.com/xml/ns/persistence/orm" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <persistence-unit name="generated">
        <class>generated.Items</class>
        <class>generated.Items$Item</class>
        <class>generated.PurchaseOrderType</class>
        <class>generated.USAddress</class>
    </persistence-unit>
</persistence>

Source Script

Jaxb

  • Creation of an instance of JAXB context with a JAXBContext.newInstance(…) call passing the context path. The context path is typically the package name of the generated classes.
// Context with the package name of the generated class as parameter
context = JAXBContext.newInstance("generated");
// A context with the class name of the root element is also possible
context = JAXBContext.newInstance(PurchaseOrderType.class);
  • Creation of the Unmarshaller which call an unmarshall action
// Creation of an Unmarshaller
final Unmarshaller unmarshaller = context.createUnmarshaller();
// The Unmarshaller unmarshal
final Object object = unmarshaller.unmarshal(new File("src/test/samples/po.xml"));
  • Cast of the object to retrieve the good type and test
// With a cast, we retrieve the final object (data type)
@SuppressWarnings("unchecked")
final PurchaseOrderType purchaseOrder = ((JAXBElement<PurchaseOrderType>) object).getValue();
// Test
System.out.println("Purchase Order Comment "+purchaseOrder.getComment());

<wrap>An instance of the generated ObjectFactory is only needed to create objects (to marshall).</note>

Jpa

Creation of an entity manager factory by passing:

  • the name of persistence unit (see META-INF/persistence.xml above)
  • a properties file (in the resource persistence.properties) to define the database-specific properties

You can define the database connection in the persistence unit itself but to keep ORM mappings should be generic, case-specific. They are be kept separately.

final Properties persistenceProperties = new Properties();
InputStream is = null;

try {
	is = getClass().getClassLoader().getResourceAsStream("persistence.properties");
	persistenceProperties.load(is);
} finally {
	if (is != null) {
		try {
			is.close();
		} catch (IOException ignored) {
		}
	}
}

entityManagerFactory = Persistence.createEntityManagerFactory(
		"generated", persistenceProperties);

persistence.properties

persistence.properties are database and JPA provider specific. See: JPA - Persistence Properties

Code

/**
 * 
 */
package main.java;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

import generated.ObjectFactory;
import generated.PurchaseOrderType;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;

/**
 * @author gerard
 *
 */
public class Main {

    private static JAXBContext context;
    private static EntityManagerFactory entityManagerFactory;
    
    /**
     * @param args
     * @throws JAXBException 
     * @throws IOException 
     */
    public static void main(String[] args) throws JAXBException, IOException {
	
	context = JAXBContext.newInstance("generated");
	new ObjectFactory();
	
	// Unmarshaller
	final Unmarshaller unmarshaller = context.createUnmarshaller();
	// Unmarshal
	final Object object = unmarshaller.unmarshal(new File("src/test/samples/po.xml"));
	// Cast
	@SuppressWarnings("unchecked")
	final PurchaseOrderType purchaseOrder = ((JAXBElement<PurchaseOrderType>) object).getValue();
	
	System.out.println("Purchase Order Comment "+purchaseOrder.getComment());
	
	final Properties persistenceProperties = new Properties();
	InputStream is = null;

	try {
		is = new FileInputStream("src/resources/persistence.properties");
		persistenceProperties.load(is);
	} finally {
		if (is != null) {
			is.close();		
		}
	}
	System.out.println("Url "+persistenceProperties.getProperty("hibernate.connection.url"));
	
	entityManagerFactory = Persistence.createEntityManagerFactory(
			"generated", persistenceProperties);
	
	final EntityManager saveManager = entityManagerFactory
		.createEntityManager();
	saveManager.getTransaction().begin();
	saveManager.persist(purchaseOrder);
	saveManager.getTransaction().commit();
	saveManager.close();
	
	final Long id = purchaseOrder.getHjid();
	System.out.println("Purchase Order Id "+id);

    }

}

Resultaat

Script output

Purchase Order Comment Hurry, my lawn is going wild!
Url jdbc:oracle:thin:@//localhost:1521/orcl.HotITem.local
Purchase Order Id 1

Database

More

Documentation / Reference

Support

javax.xml.bind.UnmarshalException: unexpected element (uri…

The fact that it doesn't unmarshal, is clear in the error message: it expects a no-namespace element <{}Repository> as opposed to <{uri:“http://www.oracle.com/obis/repository”}Repository>.

Exception in thread "main" javax.xml.bind.UnmarshalException: unexpected element (uri:"http://www.oracle.com/obis/repository", local:"BusinessModel"). Expected elements are <{}Repository>
	at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallingContext.handleEvent(UnmarshallingContext.java:662)

Powered by ComboStrap