Skip to content

Commit

Permalink
METAGEN-6 Split XML parsing code out into its own class.
Browse files Browse the repository at this point in the history
  • Loading branch information
hferentschik authored and stliu committed Nov 11, 2013
1 parent d5f15a1 commit bc1e9f1
Show file tree
Hide file tree
Showing 2 changed files with 331 additions and 289 deletions.
Expand Up @@ -17,45 +17,25 @@
*/
package org.hibernate.jpamodelgen;

import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedSourceVersion;
import static javax.lang.model.SourceVersion.RELEASE_6;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.TypeElement;
import javax.lang.model.util.Elements;
import javax.persistence.AccessType;
import javax.persistence.Embeddable;
import javax.persistence.MappedSuperclass;
import javax.tools.Diagnostic;
import javax.tools.FileObject;
import javax.tools.StandardLocation;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;

import org.xml.sax.SAXException;

import org.hibernate.jpamodelgen.annotation.AnnotationMetaEntity;
import org.hibernate.jpamodelgen.xml.XmlMetaEntity;
import org.hibernate.jpamodelgen.xml.jaxb.Entity;
import org.hibernate.jpamodelgen.xml.jaxb.EntityMappings;
import org.hibernate.jpamodelgen.xml.jaxb.ObjectFactory;
import org.hibernate.jpamodelgen.xml.jaxb.Persistence;
import org.hibernate.jpamodelgen.xml.jaxb.PersistenceUnitDefaults;
import org.hibernate.jpamodelgen.xml.jaxb.PersistenceUnitMetadata;
import org.hibernate.jpamodelgen.xml.XmlParser;

import static javax.lang.model.SourceVersion.RELEASE_6;

/**
* Main annotation processor.
Expand All @@ -68,24 +48,21 @@
@SupportedSourceVersion(RELEASE_6)
public class JPAMetaModelEntityProcessor extends AbstractProcessor {

private static final String PATH_SEPARATOR = "/";
private static final String PERSISTENCE_XML = "/META-INF/persistence.xml";
private static final String ORM_XML = "/META-INF/orm.xml";

private static final Boolean ALLOW_OTHER_PROCESSORS_TO_CLAIM_ANNOTATIONS = Boolean.FALSE;
private static final String ENTITY_ANN = javax.persistence.Entity.class.getName();
private static final String MAPPED_SUPERCLASS_ANN = MappedSuperclass.class.getName();
private static final String EMBEDDABLE_ANN = Embeddable.class.getName();
private static final AccessType DEFAULT_XML_ACCESS_TYPE = AccessType.PROPERTY;
private static final String PERSISTENCE_XML_XSD = "persistence_2_0.xsd";
private static final String ORM_XSD = "orm_2_0.xsd";

private boolean xmlProcessed = false;
private Context context;

public void init(ProcessingEnvironment env) {
super.init( env );
context = new Context( env );
context.logMessage( Diagnostic.Kind.NOTE, "Hibernate JPA 2 Static-Metamodel Generator " + Version.getVersionString() );
context.logMessage(
Diagnostic.Kind.NOTE, "Hibernate JPA 2 Static-Metamodel Generator " + Version.getVersionString()
);
}

@Override
Expand All @@ -100,7 +77,9 @@ public boolean process(final Set<? extends TypeElement> annotations,
}

if ( !xmlProcessed ) {
parsePersistenceXml();
XmlParser parser = new XmlParser( context );
parser.parsePersistenceXml();
xmlProcessed = true;
}

if ( !hostJPAAnnotations( annotations ) ) {
Expand Down Expand Up @@ -150,164 +129,6 @@ else if ( typeName.equals( MAPPED_SUPERCLASS_ANN ) ) {
return false;
}

private void parsePersistenceXml() {
Persistence persistence = parseXml( PERSISTENCE_XML, Persistence.class, PERSISTENCE_XML_XSD );
if ( persistence != null ) {
List<Persistence.PersistenceUnit> persistenceUnits = persistence.getPersistenceUnit();
for ( Persistence.PersistenceUnit unit : persistenceUnits ) {
List<String> mappingFiles = unit.getMappingFile();
for ( String mappingFile : mappingFiles ) {
parsingOrmXml( mappingFile );
}
}
}
parsingOrmXml( ORM_XML ); // /META-INF/orm.xml is implicit
xmlProcessed = true;
}

private void parsingOrmXml(String resource) {
EntityMappings mappings = parseXml( resource, EntityMappings.class, ORM_XSD );
if ( mappings == null ) {
return;
}

AccessType accessType = determineGlobalAccessType( mappings );

parseEntities( mappings, accessType );
parseEmbeddable( mappings, accessType );
parseMappedSuperClass( mappings, accessType );
}

private AccessType determineGlobalAccessType(EntityMappings mappings) {
AccessType accessType = DEFAULT_XML_ACCESS_TYPE;

if ( mappings.getAccess() != null ) {
accessType = mapXmlAccessTypeToJpaAccessType( mappings.getAccess() );
return accessType; // no need to check persistence unit default
}

PersistenceUnitMetadata meta = mappings.getPersistenceUnitMetadata();
if ( meta != null ) {
PersistenceUnitDefaults persistenceUnitDefaults = meta.getPersistenceUnitDefaults();
if ( persistenceUnitDefaults != null ) {
org.hibernate.jpamodelgen.xml.jaxb.AccessType xmlAccessType = persistenceUnitDefaults.getAccess();
if ( xmlAccessType != null ) {
accessType = mapXmlAccessTypeToJpaAccessType( xmlAccessType );
}
}
}
return accessType;
}

private AccessType mapXmlAccessTypeToJpaAccessType(org.hibernate.jpamodelgen.xml.jaxb.AccessType xmlAccessType) {
switch ( xmlAccessType ) {
case FIELD: {
return AccessType.FIELD;
}
case PROPERTY: {
return AccessType.PROPERTY;
}
}
return null;
}

private void parseEntities(EntityMappings mappings, AccessType accessType) {
String packageName = mappings.getPackage();
Collection<Entity> entities = mappings.getEntity();
for ( Entity entity : entities ) {
String fullyQualifiedClassName = packageName + "." + entity.getClazz();

if ( !xmlMappedTypeExists( fullyQualifiedClassName ) ) {
context.logMessage(
Diagnostic.Kind.WARNING,
fullyQualifiedClassName + " is mapped in xml, but class does not exists. Skipping meta model generation."
);
continue;
}

XmlMetaEntity metaEntity = new XmlMetaEntity(
entity, packageName, getXmlMappedType( fullyQualifiedClassName ),
context
);

if ( context.getMetaEntitiesToProcess().containsKey( fullyQualifiedClassName ) ) {
context.logMessage(
Diagnostic.Kind.WARNING,
fullyQualifiedClassName + " was already processed once. Skipping second occurance."
);
}
context.getMetaEntitiesToProcess().put( fullyQualifiedClassName, metaEntity );
}
}

private boolean xmlMappedTypeExists(String fullyQualifiedClassName) {
Elements utils = processingEnv.getElementUtils();
return utils.getTypeElement( fullyQualifiedClassName ) != null;
}

private TypeElement getXmlMappedType(String fullyQualifiedClassName) {
Elements utils = processingEnv.getElementUtils();
return utils.getTypeElement( fullyQualifiedClassName );
}

private void parseEmbeddable(EntityMappings mappings, AccessType accessType) {
String packageName = mappings.getPackage();
Collection<org.hibernate.jpamodelgen.xml.jaxb.Embeddable> embeddables = mappings.getEmbeddable();
for ( org.hibernate.jpamodelgen.xml.jaxb.Embeddable embeddable : embeddables ) {
String fullyQualifiedClassName = packageName + "." + embeddable.getClazz();

if ( !xmlMappedTypeExists( fullyQualifiedClassName ) ) {
context.logMessage(
Diagnostic.Kind.WARNING,
fullyQualifiedClassName + " is mapped in xml, but class does not exists. Skipping meta model generation."
);
continue;
}

XmlMetaEntity metaEntity = new XmlMetaEntity(
embeddable, packageName, getXmlMappedType( fullyQualifiedClassName ),
context
);

if ( context.getMetaSuperclassAndEmbeddableToProcess().containsKey( fullyQualifiedClassName ) ) {
context.logMessage(
Diagnostic.Kind.WARNING,
fullyQualifiedClassName + " was already processed once. Skipping second occurance."
);
}
context.getMetaSuperclassAndEmbeddableToProcess().put( fullyQualifiedClassName, metaEntity );
}
}

private void parseMappedSuperClass(EntityMappings mappings, AccessType accessType) {
String packageName = mappings.getPackage();
Collection<org.hibernate.jpamodelgen.xml.jaxb.MappedSuperclass> mappedSuperClasses = mappings.getMappedSuperclass();
for ( org.hibernate.jpamodelgen.xml.jaxb.MappedSuperclass mappedSuperClass : mappedSuperClasses ) {
String fullyQualifiedClassName = packageName + "." + mappedSuperClass.getClazz();

if ( !xmlMappedTypeExists( fullyQualifiedClassName ) ) {
context.logMessage(
Diagnostic.Kind.WARNING,
fullyQualifiedClassName + " is mapped in xml, but class does not exists. Skipping meta model generation."
);
continue;
}

XmlMetaEntity metaEntity = new XmlMetaEntity(
mappedSuperClass, packageName, getXmlMappedType( fullyQualifiedClassName ),
context
);

if ( context.getMetaSuperclassAndEmbeddableToProcess().containsKey( fullyQualifiedClassName ) ) {
context.logMessage(
Diagnostic.Kind.WARNING,
fullyQualifiedClassName + " was already processed once. Skipping second occurance."
);
}
context.getMetaSuperclassAndEmbeddableToProcess().put( fullyQualifiedClassName, metaEntity );
}
}

private void handleRootElementAnnotationMirrors(final Element element) {

List<? extends AnnotationMirror> annotationMirrors = element
Expand All @@ -332,104 +153,4 @@ else if ( annotationType.equals( MAPPED_SUPERCLASS_ANN )
}
}
}

private InputStream getInputStreamForResource(String resource) {
String pkg = getPackage( resource );
String name = getRelativeName( resource );
context.logMessage( Diagnostic.Kind.OTHER, "Reading resource " + resource );
InputStream ormStream;
try {
FileObject fileObject = processingEnv.getFiler().getResource( StandardLocation.CLASS_OUTPUT, pkg, name );
ormStream = fileObject.openInputStream();
}
catch ( IOException e1 ) {
// processingEnv.getMessager()
// .printMessage(
// Diagnostic.Kind.WARNING,
// "Could not load " + resource + " using processingEnv.getFiler().getResource(). Using classpath..."
// );

// TODO
// unfortunately, the Filer.getResource API seems not to be able to load from /META-INF. One gets a
// FilerException with the message with "Illegal name /META-INF". This means that we have to revert to
// using the classpath. This might mean that we find a persistence.xml which is 'part of another jar.
// Not sure what else we can do here
ormStream = this.getClass().getResourceAsStream( resource );
}
return ormStream;
}

/**
* Tries to open the specified xml file and return an instance of the specified class using JAXB.
*
* @param resource the xml file name
* @param clazz The type of jaxb node to return
* @param schemaName The schema to validate against (can be {@code null});
*
* @return The top level jaxb instance contained in the xml file or {@code null} in case the file could not be found.
*/
private <T> T parseXml(String resource, Class<T> clazz, String schemaName) {

InputStream stream = getInputStreamForResource( resource );

if ( stream == null ) {
context.logMessage( Diagnostic.Kind.OTHER, resource + " not found." );
return null;
}
try {
JAXBContext jc = JAXBContext.newInstance( ObjectFactory.class );
Unmarshaller unmarshaller = jc.createUnmarshaller();
if ( schemaName != null ) {
unmarshaller.setSchema( getSchema( schemaName ) );
}
return clazz.cast( unmarshaller.unmarshal( stream ) );
}
catch ( JAXBException e ) {
String message = "Error unmarshalling " + resource + " with exception :\n " + e;
context.logMessage( Diagnostic.Kind.WARNING, message );
return null;
}
catch ( Exception e ) {
String message = "Error reading " + resource + " with exception :\n " + e;
context.logMessage( Diagnostic.Kind.WARNING, message );
return null;
}
}

private String getPackage(String resourceName) {
if ( !resourceName.contains( PATH_SEPARATOR ) ) {
return "";
}
else {
return resourceName.substring( 0, resourceName.lastIndexOf( PATH_SEPARATOR ) );
}
}

private String getRelativeName(String resourceName) {
if ( !resourceName.contains( PATH_SEPARATOR ) ) {
return resourceName;
}
else {
return resourceName.substring( resourceName.lastIndexOf( PATH_SEPARATOR ) + 1 );
}
}

private Schema getSchema(String schemaName) {
Schema schema = null;
URL schemaUrl = this.getClass().getClassLoader().getResource( schemaName );
if ( schemaUrl == null ) {
return schema;
}

SchemaFactory sf = SchemaFactory.newInstance( javax.xml.XMLConstants.W3C_XML_SCHEMA_NS_URI );
try {
schema = sf.newSchema( schemaUrl );
}
catch ( SAXException e ) {
context.logMessage(
Diagnostic.Kind.WARNING, "Unable to create schema for " + schemaName + ": " + e.getMessage()
);
}
return schema;
}
}

0 comments on commit bc1e9f1

Please sign in to comment.