org.hibernate.bytecode.enhance.internal.javassist.AttributeTypeDescriptor Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of hibernate-core Show documentation
Show all versions of hibernate-core Show documentation
Hibernate's core ORM functionality
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or .
*/
package org.hibernate.bytecode.enhance.internal.javassist;
import java.util.Collection;
import java.util.Locale;
import java.util.Objects;
import javax.persistence.EmbeddedId;
import javax.persistence.Id;
import javassist.CtClass;
import javassist.CtField;
import javassist.NotFoundException;
import org.hibernate.bytecode.enhance.spi.EnhancerConstants;
/**
* utility class to generate interceptor methods
* @see org.hibernate.engine.spi.PersistentAttributeInterceptor
*
* @author Luis Barreiro
*/
public abstract class AttributeTypeDescriptor {
protected InheritanceMetadata inheritanceMetadata;
protected AttributeTypeDescriptor(InheritanceMetadata inheritanceMetadata) {
this.inheritanceMetadata = inheritanceMetadata;
}
public abstract String buildReadInterceptionBodyFragment(String fieldName);
public abstract String buildWriteInterceptionBodyFragment(String fieldName);
public String buildInLineDirtyCheckingBodyFragment(JavassistEnhancementContext context, CtField currentValue) {
StringBuilder builder = new StringBuilder();
try {
// should ignore primary keys
if ( PersistentAttributesHelper.hasAnnotation( currentValue, Id.class )
|| PersistentAttributesHelper.hasAnnotation( currentValue, EmbeddedId.class ) ) {
return "";
}
String readFragment = inheritanceMetadata.isInherited() && !inheritanceMetadata.isVisible()
? "super." + inheritanceMetadata.getReaderName() + "()"
: "this." + currentValue.getName();
if ( currentValue.getType().isPrimitive() || currentValue.getType().isEnum() ) {
// primitives || enums
builder.append( String.format( " if ( %s != $1 )", readFragment ) );
}
else {
// if the field is a collection we return since we handle that in a separate method
for ( CtClass ctClass : currentValue.getType().getInterfaces() ) {
if ( ctClass.getName().equals( Collection.class.getName() ) ) {
// if the collection is not managed we should write it to the tracker
if ( context.isMappedCollection( currentValue ) ) {
return "";
}
}
}
builder.append(
String.format(
" if ( !%s.deepEquals( %s, $1 ) )",
Objects.class.getName(),
readFragment
)
);
}
builder.append( String.format( " { %s(\"%s\"); }", EnhancerConstants.TRACKER_CHANGER_NAME, currentValue.getName() ) );
}
catch (NotFoundException ignore) {
}
return builder.toString();
}
/* --- */
/**
* factory method to get the AttributeTypeDescriptor for a particular field type
*/
public static AttributeTypeDescriptor resolve(CtClass managedCtClass, CtField persistentField) throws NotFoundException {
boolean inherited = !managedCtClass.equals( persistentField.getDeclaringClass() );
boolean visible = persistentField.visibleFrom( managedCtClass );
String readerName = EnhancerConstants.PERSISTENT_FIELD_READER_PREFIX + persistentField.getName();
String writerName = EnhancerConstants.PERSISTENT_FIELD_WRITER_PREFIX + persistentField.getName();
InheritanceMetadata inheritanceMetadata = new InheritanceMetadata( inherited, visible, readerName, writerName );
if ( CtClass.booleanType.equals( persistentField.getType() ) ) {
return new PrimitiveAttributeTypeDescriptor( inheritanceMetadata, Boolean.TYPE );
}
else if ( CtClass.byteType.equals( persistentField.getType() )) {
return new PrimitiveAttributeTypeDescriptor( inheritanceMetadata, Byte.TYPE );
}
else if ( CtClass.charType.equals( persistentField.getType() ) ) {
return new PrimitiveAttributeTypeDescriptor( inheritanceMetadata, Character.TYPE );
}
else if ( CtClass.shortType.equals( persistentField.getType() ) ) {
return new PrimitiveAttributeTypeDescriptor( inheritanceMetadata, Short.TYPE );
}
else if ( CtClass.intType.equals( persistentField.getType() ) ) {
return new PrimitiveAttributeTypeDescriptor( inheritanceMetadata, Integer.TYPE );
}
else if ( CtClass.longType.equals( persistentField.getType() ) ) {
return new PrimitiveAttributeTypeDescriptor( inheritanceMetadata, Long.TYPE );
}
else if ( CtClass.doubleType.equals( persistentField.getType() ) ) {
return new PrimitiveAttributeTypeDescriptor( inheritanceMetadata, Double.TYPE );
}
else if ( CtClass.floatType.equals( persistentField.getType() ) ) {
return new PrimitiveAttributeTypeDescriptor( inheritanceMetadata, Float.TYPE );
}
else {
return new ObjectAttributeTypeDescriptor( inheritanceMetadata, persistentField.getType() );
}
}
/* --- */
/**
* AttributeTypeDescriptor for non primitive types
*/
private static class ObjectAttributeTypeDescriptor extends AttributeTypeDescriptor {
private final String type;
private ObjectAttributeTypeDescriptor(InheritanceMetadata inheritanceMetadata, CtClass concreteType) {
super( inheritanceMetadata );
this.type = concreteType.getName();
}
@Override
public String buildReadInterceptionBodyFragment(String fieldName) {
if ( inheritanceMetadata.isInherited() && !inheritanceMetadata.isVisible() ) {
return String.format(
" if( %3$s() != null ) { super.%5$s( (%2$s) %3$s().readObject(this, \"%1$s\", super.%4$s())); }%n",
fieldName,
type,
EnhancerConstants.INTERCEPTOR_GETTER_NAME,
inheritanceMetadata.getReaderName(),
inheritanceMetadata.getWriterName() );
}
else {
return String.format(
" if ( %3$s() != null ) { this.%1$s = (%2$s) %3$s().readObject(this, \"%1$s\", this.%1$s); }%n",
fieldName,
type,
EnhancerConstants.INTERCEPTOR_GETTER_NAME );
}
}
@Override
public String buildWriteInterceptionBodyFragment(String fieldName) {
if ( inheritanceMetadata.isInherited() && !inheritanceMetadata.isVisible() ) {
return String.format(
" %2$s localVar = $1;%n" +
" if ( %3$s() != null ) { localVar = (%2$s) %3$s().writeObject(this, \"%1$s\", super.%4$s(), $1); }%n" +
" super.%5$s(localVar);",
fieldName,
type,
EnhancerConstants.INTERCEPTOR_GETTER_NAME,
inheritanceMetadata.getReaderName(),
inheritanceMetadata.getWriterName() );
}
else {
return String.format(
" %2$s localVar = $1;%n" +
" if ( %3$s() != null ) { localVar = (%2$s) %3$s().writeObject(this, \"%1$s\", this.%1$s, $1); }%n" +
" this.%1$s = localVar;",
fieldName,
type,
EnhancerConstants.INTERCEPTOR_GETTER_NAME );
}
}
}
/**
* AttributeTypeDescriptor for primitive types
*/
private static class PrimitiveAttributeTypeDescriptor extends AttributeTypeDescriptor {
private final String type;
private PrimitiveAttributeTypeDescriptor(InheritanceMetadata inheritanceMetadata, Class primitiveType) {
super( inheritanceMetadata );
if ( !primitiveType.isPrimitive() ) {
throw new IllegalArgumentException( "Primitive attribute type descriptor can only be used on primitive types" );
}
// capitalize first letter
this.type = primitiveType.getSimpleName().substring( 0, 1 ).toUpperCase( Locale.ROOT ) + primitiveType.getSimpleName().substring( 1 );
}
@Override
public String buildReadInterceptionBodyFragment(String fieldName) {
if ( inheritanceMetadata.isInherited() && !inheritanceMetadata.isVisible() ) {
return String.format(
" if (%3$s() != null ) { super.%5$s( %3$s().read%2$s(this, \"%1$s\", super.%4$s())); }",
fieldName,
type,
EnhancerConstants.INTERCEPTOR_GETTER_NAME,
inheritanceMetadata.getReaderName(),
inheritanceMetadata.getWriterName() );
}
else {
return String.format(
" if (%3$s() != null ) { this.%1$s = %3$s().read%2$s(this, \"%1$s\", this.%1$s); }",
fieldName,
type,
EnhancerConstants.INTERCEPTOR_GETTER_NAME );
}
}
@Override
public String buildWriteInterceptionBodyFragment(String fieldName) {
if ( inheritanceMetadata.isInherited() && !inheritanceMetadata.isVisible() ) {
return String.format(
" %2$s localVar = $1;%n" +
" if ( %4$s() != null ) { localVar = %4$s().write%3$s(this, \"%1$s\", super.%5$s(), $1); }%n" +
" super.%6$s(localVar);",
fieldName,
type.toLowerCase( Locale.ROOT ),
type,
EnhancerConstants.INTERCEPTOR_GETTER_NAME,
inheritanceMetadata.getReaderName(),
inheritanceMetadata.getWriterName() );
}
else {
return String.format(
" %2$s localVar = $1;%n" +
" if ( %4$s() != null ) { localVar = %4$s().write%3$s(this, \"%1$s\", this.%1$s, $1); }%n" +
" this.%1$s = localVar;",
fieldName,
type.toLowerCase( Locale.ROOT ),
type,
EnhancerConstants.INTERCEPTOR_GETTER_NAME
);
}
}
}
//
private static class InheritanceMetadata {
private boolean inherited;
private boolean visible;
private String readerName;
private String writerName;
public InheritanceMetadata(boolean inherited, boolean visible, String readerName, String writerName) {
this.inherited = inherited;
this.visible = visible;
this.readerName = readerName;
this.writerName = writerName;
}
public boolean isInherited() {
return inherited;
}
public boolean isVisible() {
return visible;
}
public String getReaderName() {
return readerName;
}
public String getWriterName() {
return writerName;
}
}
}