METAGEN-24 Create a mechanism to check whether xml files have changed

This commit is contained in:
Hardy Ferentschik 2010-02-18 01:07:46 +00:00 committed by Strong Liu
parent 443ae2de29
commit 22db734897
14 changed files with 230 additions and 36 deletions

View File

@ -1,6 +1,4 @@
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 125 KiB

After

Width:  |  Height:  |  Size: 173 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 333 KiB

After

Width:  |  Height:  |  Size: 365 KiB

View File

@ -92,7 +92,7 @@ public class Order_ {
<example id="criteria-example" label="">
<title>Example of typesafe query using the metamodel class
<classname>Order_</classname> </title>
<classname>Order_</classname></title>
<programlisting>CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery&lt;Order&gt; cq = cb.createQuery(Order.class);
@ -109,7 +109,7 @@ cq.where( cb.equal(itemNode.get(Item_.id), 5 ) ).distinct(true);
url="http://jcp.org/en/jsr/detail?id=317">JPA 2 specification</ulink>
and its definition is included for completeness in the following
paragraphs . Feel free to skip ahead to <xref linkend="chapter-usage" />
if you are not interested into the gory details. </para>
if you are not interested into the gory details.</para>
<para>The annotation processor produces for every managed class in the
persistence unit a metamodel class based on these rules:</para>
@ -188,8 +188,8 @@ cq.where( cb.equal(itemNode.get(Item_.id), 5 ) ).distinct(true);
<chapter id="chapter-usage">
<title>Usage</title>
<para> The jar file for the annotation processor can be found in the
<ulink url="http://repository.jboss.com/">JBoss Maven repository</ulink>
<para>The jar file for the annotation processor can be found in the <ulink
url="http://repository.jboss.com/">JBoss Maven repository</ulink>
under:</para>
<example id="maven-dependency" label="">
@ -233,7 +233,7 @@ cq.where( cb.equal(itemNode.get(Item_.id), 5 ) ).distinct(true);
url="http://ant.apache.org/manual/CoreTasks/javac.html">Ant Javac
Task</ulink> can be configured to just run annotation
processing.<example id="javac-task-example">
<title>Ant Javac Task configuration </title>
<title>Ant Javac Task configuration</title>
<programlisting>&lt;javac srcdir="${src.dir}"
destdir="${target.dir}"
@ -407,7 +407,12 @@ cq.where( cb.equal(itemNode.get(Item_.id), 5 ) ).distinct(true);
<section>
<title>NetBeans</title>
<para>TODO</para>
<para>Netbeans support for annotation processors is at the time of
this wrinting still in the making. Refer to NetBeans issues <ulink
url="http://www.netbeans.org/issues/show_bug.cgi?id=111065">111065</ulink>,
<ulink
url="http://www.netbeans.org/issues/show_bug.cgi?id=111293">111293</ulink>
and <ulink url="???">111294</ulink>.</para>
</section>
</section>
@ -455,6 +460,22 @@ cq.where( cb.equal(itemNode.get(Item_.id), 5 ) ).distinct(true);
mapping file names. Even when this option is specified
<filename>/META-INF/orm.xml</filename> is implicit.</entry>
</row>
<row>
<entry>lazyXmlParsing</entry>
<entry>Possible values are <literal>true</literal> or
<literal>false</literal>. If set to <literal>true</literal>
the annotation processor tries to determine whether any of the
xml files has changed between invocations and if unchanged
skips the xml parsing. This feature is experimental and
contains the risk of wron results in some cases of mixed mode
configurations. To determine wether a file has been modified a
temporary file
<filename>Hibernate-Static-Metamodel-Generator.tmp</filename>
is used. This file gets created in the
<literal>java.io.tmpdir</literal> directory.</entry>
</row>
</tbody>
</tgroup>
</table></para>

View File

@ -56,6 +56,7 @@ public class Context {
private final ProcessingEnvironment pe;
private final boolean logDebug;
private final boolean lazyXmlParsing;
private final String persistenceXmlLocation;
private final List<String> ormXmlFiles;
@ -90,6 +91,7 @@ public class Context {
ormXmlFiles = Collections.emptyList();
}
lazyXmlParsing = Boolean.parseBoolean( pe.getOptions().get( JPAMetaModelEntityProcessor.LAZY_XML_PARSING ) );
logDebug = Boolean.parseBoolean( pe.getOptions().get( JPAMetaModelEntityProcessor.DEBUG_OPTION ) );
}
@ -125,8 +127,8 @@ public class Context {
return metaEntities.values();
}
public void addMetaEntity(String fcqn, MetaEntity metaEntity) {
metaEntities.put( fcqn, metaEntity );
public void addMetaEntity(String fqcn, MetaEntity metaEntity) {
metaEntities.put( fqcn, metaEntity );
}
public boolean containsMetaEmbeddable(String fqcn) {
@ -181,12 +183,17 @@ public class Context {
this.persistenceUnitDefaultAccessType = persistenceUnitDefaultAccessType;
}
public boolean doLazyXmlParsing() {
return lazyXmlParsing;
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder();
sb.append( "Context" );
sb.append( "{accessTypeInformation=" ).append( accessTypeInformation );
sb.append( ", logDebug=" ).append( logDebug );
sb.append( ", lazyXmlParsing=" ).append( lazyXmlParsing );
sb.append( ", isPersistenceUnitCompletelyXmlConfigured=" ).append( isPersistenceUnitCompletelyXmlConfigured );
sb.append( ", ormXmlFiles=" ).append( ormXmlFiles );
sb.append( ", persistenceXmlLocation='" ).append( persistenceXmlLocation ).append( '\'' );

View File

@ -64,16 +64,22 @@ import static javax.lang.model.SourceVersion.RELEASE_6;
@SupportedOptions({
JPAMetaModelEntityProcessor.DEBUG_OPTION,
JPAMetaModelEntityProcessor.PERSISTENCE_XML_OPTION,
JPAMetaModelEntityProcessor.ORM_XML_OPTION
JPAMetaModelEntityProcessor.ORM_XML_OPTION,
JPAMetaModelEntityProcessor.FULLY_ANNOTATION_CONFIGURED_OPTION,
JPAMetaModelEntityProcessor.LAZY_XML_PARSING
})
public class JPAMetaModelEntityProcessor extends AbstractProcessor {
public static final String DEBUG_OPTION = "debug";
public static final String PERSISTENCE_XML_OPTION = "persistenceXml";
public static final String ORM_XML_OPTION = "ormXmlList";
public static final String FULLY_ANNOTATION_CONFIGURED_OPTION = "fullyAnnotationConfigured";
public static final String LAZY_XML_PARSING = "lazyXmlParsing";
private static final Boolean ALLOW_OTHER_PROCESSORS_TO_CLAIM_ANNOTATIONS = Boolean.FALSE;
private boolean xmlProcessed = false;
private Context context;
private boolean fullyAnnotationConfigured = false;
public void init(ProcessingEnvironment env) {
super.init( env );
@ -81,12 +87,13 @@ public class JPAMetaModelEntityProcessor extends AbstractProcessor {
context.logMessage(
Diagnostic.Kind.NOTE, "Hibernate JPA 2 Static-Metamodel Generator " + Version.getVersionString()
);
String tmp = env.getOptions().get( JPAMetaModelEntityProcessor.FULLY_ANNOTATION_CONFIGURED_OPTION );
fullyAnnotationConfigured = Boolean.parseBoolean( tmp );
}
@Override
public boolean process(final Set<? extends TypeElement> annotations,
final RoundEnvironment roundEnvironment) {
public boolean process(final Set<? extends TypeElement> annotations, final RoundEnvironment roundEnvironment) {
if ( roundEnvironment.processingOver() ) {
context.logMessage( Diagnostic.Kind.OTHER, "Last processing round." );
createMetaModelClasses();
@ -94,7 +101,7 @@ public class JPAMetaModelEntityProcessor extends AbstractProcessor {
return ALLOW_OTHER_PROCESSORS_TO_CLAIM_ANNOTATIONS;
}
if ( !xmlProcessed ) {
if ( !fullyAnnotationConfigured && !xmlProcessed ) {
XmlParser parser = new XmlParser( context );
parser.parseXml();
xmlProcessed = true;
@ -156,7 +163,7 @@ public class JPAMetaModelEntityProcessor extends AbstractProcessor {
for ( Element subElement : ElementFilter.fieldsIn( entity.getTypeElement().getEnclosedElements() ) ) {
TypeMirror mirror = subElement.asType();
if ( !TypeKind.DECLARED.equals( mirror.getKind() ) ) {
continue;
continue;
}
boolean contains = mirror.accept( visitor, subElement );
if ( contains ) {

View File

@ -0,0 +1,73 @@
// $Id:$
/*
* JBoss, Home of Professional Open Source
* Copyright 2009, Red Hat, Inc. and/or its affiliates, and individual contributors
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.hibernate.jpamodelgen.util;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
/**
* @author Hardy Ferentschik
*/
public class FileTimeStampChecker implements Serializable {
Map<String, Long> lastModifiedCache;
public FileTimeStampChecker() {
lastModifiedCache = new HashMap<String, Long>();
}
public void add(String fileName, Long lastModified) {
lastModifiedCache.put( fileName, lastModified );
}
@Override
public boolean equals(Object o) {
if ( this == o ) {
return true;
}
if ( o == null || getClass() != o.getClass() ) {
return false;
}
FileTimeStampChecker that = ( FileTimeStampChecker ) o;
if ( !lastModifiedCache.equals( that.lastModifiedCache ) ) {
return false;
}
return true;
}
@Override
public int hashCode() {
return lastModifiedCache.hashCode();
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder();
sb.append( "FileTimeStampChecker" );
sb.append( "{lastModifiedCache=" ).append( lastModifiedCache );
sb.append( '}' );
return sb.toString();
}
}

View File

@ -1,4 +1,4 @@
// $Id: XmlMetaEntity.java 18753 2010-02-09 21:29:34Z hardy.ferentschik $
// $Id$
/*
* JBoss, Home of Professional Open Source
* Copyright 2008, Red Hat Middleware LLC, and individual contributors

View File

@ -360,6 +360,9 @@ public class XmlMetaEntity implements MetaEntity {
}
private void parseEmbeddableAttributes(EmbeddableAttributes attributes) {
if ( attributes == null ) {
return;
}
for ( Basic basic : attributes.getBasic() ) {
parseBasic( basic );
}

View File

@ -17,8 +17,15 @@
*/
package org.hibernate.jpamodelgen.xml;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
@ -40,6 +47,7 @@ import org.xml.sax.SAXException;
import org.hibernate.jpamodelgen.AccessTypeInformation;
import org.hibernate.jpamodelgen.Context;
import org.hibernate.jpamodelgen.util.Constants;
import org.hibernate.jpamodelgen.util.FileTimeStampChecker;
import org.hibernate.jpamodelgen.util.StringUtil;
import org.hibernate.jpamodelgen.util.TypeUtils;
import org.hibernate.jpamodelgen.xml.jaxb.Entity;
@ -56,6 +64,7 @@ public class XmlParser {
private static final String ORM_XML = "/META-INF/orm.xml";
private static final String PERSISTENCE_XML_XSD = "persistence_2_0.xsd";
private static final String ORM_XSD = "orm_2_0.xsd";
private static final String SERIALIZATION_FILE_NAME = "Hibernate-Static-Metamodel-Generator.tmp";
private Context context;
private List<EntityMappings> entityMappings;
@ -66,7 +75,13 @@ public class XmlParser {
}
public void parseXml() {
collectAllEntityMappings();
Collection<String> mappingFileNames = determineMappingFileNames();
if ( context.doLazyXmlParsing() && mappingFilesUnchanged( mappingFileNames ) ) {
return;
}
loadEntityMappings( mappingFileNames );
determineDefaultAccessTypeAndMetaCompleteness();
determineXmlAccessTypes();
if ( !context.isPersistenceUnitCompletelyXmlConfigured() ) {
@ -83,35 +98,107 @@ public class XmlParser {
}
}
private void collectAllEntityMappings() {
private Collection<String> determineMappingFileNames() {
Collection<String> mappingFileNames = new ArrayList<String>();
Persistence persistence = parseXml(
context.getPersistenceXmlLocation(), 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 ) {
loadEntityMappings( mappingFile );
}
mappingFileNames.addAll( unit.getMappingFile() );
}
}
// /META-INF/orm.xml is implicit
loadEntityMappings( ORM_XML );
mappingFileNames.add( ORM_XML );
// not really part of the official spec, but the processor allows to specify mapping files directly as
// command line options
for ( String optionalOrmFiles : context.getOrmXmlFiles() ) {
loadEntityMappings( optionalOrmFiles );
mappingFileNames.addAll( context.getOrmXmlFiles() );
return mappingFileNames;
}
private void loadEntityMappings(Collection<String> mappingFileNames) {
for ( String mappingFile : mappingFileNames ) {
EntityMappings mapping = parseXml( mappingFile, EntityMappings.class, ORM_XSD );
if ( mapping != null ) {
entityMappings.add( mapping );
}
}
}
private void loadEntityMappings(String resource) {
EntityMappings mapping = parseXml( resource, EntityMappings.class, ORM_XSD );
if ( mapping != null ) {
entityMappings.add( mapping );
private boolean mappingFilesUnchanged(Collection<String> mappingFileNames) {
boolean mappingFilesUnchanged = false;
FileTimeStampChecker fileStampCheck = new FileTimeStampChecker();
for ( String mappingFile : mappingFileNames ) {
try {
URL url = this.getClass().getResource( mappingFile );
if ( url == null ) {
continue;
}
File file = new File( url.toURI() );
context.logMessage( Diagnostic.Kind.OTHER, "Check file " + mappingFile );
if ( file.exists() ) {
fileStampCheck.add( mappingFile, file.lastModified() );
}
}
catch ( URISyntaxException e ) {
// in doubt return false
return false;
}
}
FileTimeStampChecker serializedTimeStampCheck = loadTimeStampCache();
if ( serializedTimeStampCheck.equals( fileStampCheck ) ) {
context.logMessage( Diagnostic.Kind.OTHER, "XML parsing will be skipped due to unchanged xml files" );
mappingFilesUnchanged = true;
}
else {
saveTimeStampCache( fileStampCheck );
}
return mappingFilesUnchanged;
}
private void saveTimeStampCache(FileTimeStampChecker fileStampCheck) {
try {
File file = getSerializationTmpFile();
ObjectOutput out = new ObjectOutputStream( new FileOutputStream( file ) );
out.writeObject( fileStampCheck );
out.close();
context.logMessage(
Diagnostic.Kind.OTHER, "Serialized " + fileStampCheck + " into " + file.getAbsolutePath()
);
}
catch ( IOException e ) {
// ignore - if the serialization failed we just have to keep parsing the xml
context.logMessage( Diagnostic.Kind.OTHER, "Error serializing " + fileStampCheck );
}
}
private File getSerializationTmpFile() {
File tmpDir = new File( System.getProperty( "java.io.tmpdir" ) );
return new File( tmpDir, SERIALIZATION_FILE_NAME );
}
private FileTimeStampChecker loadTimeStampCache() {
FileTimeStampChecker serializedTimeStampCheck = new FileTimeStampChecker();
File file = null;
try {
file = getSerializationTmpFile();
if ( file.exists() ) {
ObjectInputStream in = new ObjectInputStream( new FileInputStream( file ) );
serializedTimeStampCheck = ( FileTimeStampChecker ) in.readObject();
in.close();
}
}
catch ( Exception e ) {
// ignore - if the de-serialization failed we just have to keep parsing the xml
context.logMessage( Diagnostic.Kind.OTHER, "Error de-serializing " + file );
}
return serializedTimeStampCheck;
}
private void parseEntities(Collection<Entity> entities, String defaultPackageName) {
@ -254,7 +341,6 @@ public class XmlParser {
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 = context.getProcessingEnvironment()

View File

@ -1,4 +1,4 @@
// $Id: Image.java 17903 2009-11-04 13:22:37Z hardy.ferentschik $
// $Id$
/*
* JBoss, Home of Professional Open Source
* Copyright 2008, Red Hat Middleware LLC, and individual contributors

View File

@ -1,4 +1,4 @@
// $Id: MixedModeMappingTest.java 18683 2010-02-02 21:51:40Z hardy.ferentschik $
// $Id$
/*
* JBoss, Home of Professional Open Source
* Copyright 2008, Red Hat Middleware LLC, and individual contributors

View File

@ -1,4 +1,4 @@
// $Id: RawTypesTest.java 18664 2010-01-28 16:56:51Z hardy.ferentschik $
// $Id$
/*
* JBoss, Home of Professional Open Source
* Copyright 2008, Red Hat Middleware LLC, and individual contributors

View File

@ -132,7 +132,6 @@ public abstract class CompilationTest {
builder.append( entry.getValue() );
options.add( builder.toString() );
}
options.add( "-Adebug=true" );
return options;
}