Tuesday, August 30, 2011

Mapping XMLTYPE

A recent posting on the TopLink Forum made it clear that previous descriptions of how to map a JPA entity attribute of type org.w3c.dom.Document to an Oracle database XMLTYPE column didn't provide enough information for schema (DDL) generation. So I thought I'd post an example that does. In the current 2.3.0 release of EclipseLink a mapping to XMLTYPE must be configured programatically through a descriptor customizer but declarative annotation and XML configuration support is scheduled for an upcoming release.

Here's a simple entity with an XML document 'resume' attribute:

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;

import org.eclipse.persistence.annotations.Customizer;
import org.w3c.dom.Document;

@Entity
@Customizer(XMLTypeAttributeCustomizer.class)
public class JobCandidate {
	@Id
	@GeneratedValue
	private long id;

	private Document resume;

	public long getId() {
		return id;
	}

	public void setId(final long id) {
		this.id = id;
	}

	public Document getMessage() {
		return resume;
	}

	public void setMessage(Document message) {
		this.resume = message;
	}
}


And here is a customizer class that will redefine the mapping for the resume attribute to be an EclipseLink DirectToXMLTypeMapping:

import org.eclipse.persistence.config.DescriptorCustomizer;
import org.eclipse.persistence.descriptors.ClassDescriptor;
import org.eclipse.persistence.mappings.xdb.DirectToXMLTypeMapping;

public class XMLTypeAttributeCustomizer implements DescriptorCustomizer {
	@Override
	public void customize(final ClassDescriptor descriptor) throws Exception {
		// Remove JPA default Basic mapping
		descriptor.removeMappingForAttributeName("resume");
		final DirectToXMLTypeMapping mapping = new DirectToXMLTypeMapping();
		mapping.setAttributeName("resume");
		mapping.setFieldName("RESUME");
		mapping.getField().setColumnDefinition("sys.XMLTYPE");
		descriptor.addMapping(mapping);
	}
}

The hightlighted line sets the database type of the mapping which is used by EclipseLink DDL generation and produces:
[EL Fine]: CREATE TABLE JOBCANDIDATE (ID NUMBER(19) NOT NULL, RESUME sys.XMLTYPE, PRIMARY KEY (ID))

3 comments:

Marco Gralike said...

Do not create an XMLType (CLOB storage) if you want performance... use binary XML..

Anonymous said...

Thank you for this tuto! It's very helpfull.

I did exactly the same, and I get the following jpa exception :
org.hibernate.MappingException: Could not determine type for: org.w3c.dom.Document, at table: MyTable, for columns: [org.hibernate.mapping.Column(MyXml)

Did something is missing?

Thank you in advance.

Shaun Smith said...

This is a TopLink (now EclipseLink) feature. It isn't supported by Hibernate.