HHH-8354 added new dirty-checking options to newly cherry-picked plugins

This commit is contained in:
Brett Meyer 2013-11-21 15:35:24 -05:00
parent a0e242992b
commit 492ea5d2a5
2 changed files with 159 additions and 115 deletions

View File

@ -29,7 +29,6 @@ import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
@ -37,17 +36,20 @@ import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtField;
import javax.persistence.ElementCollection;
import javax.persistence.Embeddable;
import javax.persistence.Entity;
import javax.persistence.ManyToMany;
import javax.persistence.OneToMany;
import javax.persistence.Transient;
import org.hibernate.bytecode.enhance.spi.EnhancementContext;
import org.hibernate.bytecode.enhance.spi.Enhancer;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.hibernate.bytecode.enhance.spi.EnhancementContext;
import org.hibernate.bytecode.enhance.spi.Enhancer;
/**
* This plugin will enhance Entity objects.
@ -55,13 +57,14 @@ import org.apache.maven.plugins.annotations.Parameter;
* @author Jeremy Whiting
*/
@Mojo(name = "enhance")
public class MavenEnhancePlugin extends AbstractMojo {
public class MavenEnhancePlugin extends AbstractMojo implements EnhancementContext {
/**
* The contexts to use during enhancement.
*/
private List<File> classes = new ArrayList<File>();
private ClassPool pool = new ClassPool( false );
private final Enhancer enhancer = new Enhancer( this);
private static final String CLASS_EXTENSION = ".class";
@ -74,57 +77,9 @@ public class MavenEnhancePlugin extends AbstractMojo {
File root = new File( this.dir );
walkDir( root );
Enhancer enhancer = new Enhancer( new EnhancementContext() {
private ClassLoader overridden;
public ClassLoader getLoadingClassLoader() {
if ( null == this.overridden ) {
return getClass().getClassLoader();
}
else {
return this.overridden;
}
}
public void setClassLoader(ClassLoader loader) {
this.overridden = loader;
}
public boolean isEntityClass(CtClass classDescriptor) {
return true;
}
public boolean hasLazyLoadableAttributes(CtClass classDescriptor) {
return true;
}
public boolean isLazyLoadable(CtField field) {
return true;
}
public boolean isCompositeClass(CtClass classDescriptor) {
return false;
}
public boolean doDirtyCheckingInline(CtClass classDescriptor) {
return false;
}
public CtField[] order(CtField[] fields) {
// TODO: load ordering from configuration.
return fields;
}
public boolean isPersistentField(CtField ctField) {
return !ctField.hasAnnotation( Transient.class );
}
} );
if ( 0 < classes.size() ) {
for ( File file : classes ) {
enhanceClass( enhancer, file );
processClassFile(file);
}
}
@ -152,6 +107,7 @@ public class MavenEnhancePlugin extends AbstractMojo {
}
private void walkDir(File dir, FileFilter classesFilter, FileFilter dirFilter) {
File[] dirs = dir.listFiles( dirFilter );
for ( int i = 0; i < dirs.length; i++ ) {
walkDir( dirs[i], classesFilter, dirFilter );
@ -163,72 +119,146 @@ public class MavenEnhancePlugin extends AbstractMojo {
}
}
private void enhanceClass(Enhancer enhancer, File file) {
byte[] enhancedBytecode = null;
InputStream is = null;
CtClass clas = null;
/**
* Atm only process files annotated with either @Entity or @Embeddable
* @param javaClassFile
*/
private void processClassFile(File javaClassFile)
throws MojoExecutionException {
try {
is = new FileInputStream( file.toString() );
clas = getClassPool().makeClass( is );
if ( !clas.hasAnnotation( Entity.class ) ) {
getLog().debug( "Class $file not an annotated Entity class. skipping..." );
}
final CtClass ctClass = getClassPool().makeClass( new FileInputStream( javaClassFile ) );
if(this.isEntityClass(ctClass))
processEntityClassFile(javaClassFile, ctClass);
else if(this.isCompositeClass(ctClass))
processCompositeClassFile(javaClassFile, ctClass);
}
catch (IOException e) {
throw new MojoExecutionException(
String.format( "Error processing included file [%s]", javaClassFile.getAbsolutePath() ), e );
}
}
private void processEntityClassFile(File javaClassFile, CtClass ctClass ) {
try {
byte[] result = enhancer.enhance( ctClass.getName(), ctClass.toBytecode() );
if(result != null)
writeEnhancedClass(javaClassFile, result);
}
catch (Exception e) {
getLog().error( "Unable to enhance class [" + ctClass.getName() + "]", e);
return;
}
}
private void processCompositeClassFile(File javaClassFile, CtClass ctClass) {
try {
byte[] result = enhancer.enhanceComposite(ctClass.getName(), ctClass.toBytecode());
if(result != null)
writeEnhancedClass(javaClassFile, result);
}
catch (Exception e) {
getLog().error( "Unable to enhance class [" + ctClass.getName() + "]", e);
return;
}
}
private void writeEnhancedClass(File javaClassFile, byte[] result)
throws MojoExecutionException {
try {
if ( javaClassFile.delete() ) {
if ( ! javaClassFile.createNewFile() ) {
getLog().error( "Unable to recreate class file [" + javaClassFile.getName() + "]");
}
}
else {
enhancedBytecode = enhancer.enhance( clas.getName(), clas.toBytecode() );
getLog().error( "Unable to delete class file [" + javaClassFile.getName() + "]");
}
}
catch (Exception e) {
getLog().error( "Unable to enhance class [${file.toString()}]", e );
return;
}
finally {
FileOutputStream outputStream = new FileOutputStream( javaClassFile, false );
try {
if ( null != is )
is.close();
}
catch (IOException ioe) {}
}
if ( null != enhancedBytecode ) {
if ( file.delete() ) {
try {
if ( !file.createNewFile() ) {
getLog().error( "Unable to recreate class file [" + clas.getName() + "]" );
}
}
catch (IOException ioe) {
}
}
else {
getLog().error( "Unable to delete class file [" + clas.getName() + "]" );
}
FileOutputStream outputStream = null;
try {
outputStream = new FileOutputStream( file, false );
outputStream.write( enhancedBytecode );
outputStream.write( result);
outputStream.flush();
}
catch (IOException ioe) {
}
finally {
try {
if ( outputStream != null )
outputStream.close();
clas.detach();// release memory
outputStream.close();
}
catch (IOException ignore) {
catch ( IOException ignore) {
}
}
}
}
public void setDir(String dir) {
if ( null != dir && !"".equals( dir.trim() ) ) {
this.dir = dir;
}
}
}
catch (FileNotFoundException ignore) {
// should not ever happen because of explicit checks
}
catch (IOException e) {
throw new MojoExecutionException(
String.format( "Error processing included file [%s]", javaClassFile.getAbsolutePath() ), e );
}
}
private ClassPool getClassPool() {
return this.pool;
}
private boolean shouldInclude(CtClass ctClass) {
// we currently only handle entity enhancement
return ctClass.hasAnnotation( Entity.class );
}
@Override
public ClassLoader getLoadingClassLoader() {
return getClass().getClassLoader();
}
@Override
public boolean isEntityClass(CtClass classDescriptor) {
return classDescriptor.hasAnnotation(Entity.class);
}
@Override
public boolean isCompositeClass(CtClass classDescriptor) {
return classDescriptor.hasAnnotation(Embeddable.class);
}
@Override
public boolean doDirtyCheckingInline(CtClass classDescriptor) {
return true;
}
@Override
public boolean hasLazyLoadableAttributes(CtClass classDescriptor) {
return true;
}
@Override
public boolean isLazyLoadable(CtField field) {
return true;
}
@Override
public boolean isPersistentField(CtField ctField) {
// current check is to look for @Transient
return ! ctField.hasAnnotation( Transient.class );
}
@Override
public boolean isMappedCollection(CtField field) {
try {
return (field.getAnnotation(OneToMany.class) != null ||
field.getAnnotation(ManyToMany.class) != null ||
field.getAnnotation(ElementCollection.class) != null);
}
catch (ClassNotFoundException e) {
return false;
}
}
@Override
public CtField[] order(CtField[] persistentFields) {
// for now...
return persistentFields;
// eventually needs to consult the Hibernate metamodel for proper ordering
}
}

View File

@ -23,19 +23,22 @@
*/
package org.hibernate.bytecode.enhance.plugins
import org.hibernate.bytecode.enhance.spi.Enhancer
import org.hibernate.bytecode.enhance.spi.EnhancementContext
import javassist.ClassPool
import javassist.CtClass
import javassist.CtField
import javax.persistence.Transient
import javax.persistence.ElementCollection
import javax.persistence.Entity
import java.io.FileInputStream
import java.io.FileOutputStream
import javax.persistence.ManyToMany
import javax.persistence.OneToMany
import javax.persistence.Transient
import org.gradle.api.DefaultTask
import org.gradle.api.file.FileTree
import org.gradle.api.plugins.Convention
import org.gradle.api.tasks.TaskAction
import org.gradle.api.file.FileTree
import org.hibernate.bytecode.enhance.spi.EnhancementContext
import org.hibernate.bytecode.enhance.spi.Enhancer
/**
* Plugin to enhance Entities using the context(s) to determine
@ -136,7 +139,7 @@ public class EnhanceTask extends DefaultTask implements EnhancementContext {
return false;
}
public boolean doDirtyCheckingInline(CtClass classDescriptor) {
return false;
return true;
}
public CtField[] order(CtField[] fields) {
@ -144,6 +147,17 @@ public class EnhanceTask extends DefaultTask implements EnhancementContext {
return fields;
}
public boolean isMappedCollection(CtField field) {
try {
return (field.getAnnotation(OneToMany.class) != null ||
field.getAnnotation(ManyToMany.class) != null ||
field.getAnnotation(ElementCollection.class) != null);
}
catch (ClassNotFoundException e) {
return false;
}
}
public boolean isPersistentField(CtField ctField) {
return !ctField.hasAnnotation( Transient.class );
}