Skip to content

Commit

Permalink
HHH-10981 - Support private persistent fields in @MappedSuperclass
Browse files Browse the repository at this point in the history
  • Loading branch information
barreiro committed Jan 26, 2017
1 parent a93edc0 commit e41867b
Show file tree
Hide file tree
Showing 5 changed files with 330 additions and 115 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -27,22 +27,32 @@
*/
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(EnhancementContext context, CtField currentValue) {
final StringBuilder builder = new StringBuilder();
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)", currentValue.getName() ) );
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
Expand All @@ -58,14 +68,13 @@ public String buildInLineDirtyCheckingBodyFragment(EnhancementContext context, C
String.format(
" if ( !%s.areEqual( %s, $1 ) )",
EqualsHelper.class.getName(),
currentValue.getName()
readFragment
)
);
}
builder.append( String.format( " { %s(\"%s\"); }", EnhancerConstants.TRACKER_CHANGER_NAME, currentValue.getName() ) );
}
catch (NotFoundException e) {
e.printStackTrace();
catch (NotFoundException ignore) {
}
return builder.toString();
}
Expand All @@ -75,33 +84,39 @@ public String buildInLineDirtyCheckingBodyFragment(EnhancementContext context, C
/**
* factory method to get the AttributeTypeDescriptor for a particular field type
*/
public static AttributeTypeDescriptor resolve(CtField persistentField) throws NotFoundException {
if ( persistentField.getType() == CtClass.booleanType ) {
return new PrimitiveAttributeTypeDescriptor( Boolean.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 ( persistentField.getType() == CtClass.byteType ) {
return new PrimitiveAttributeTypeDescriptor( Byte.TYPE );
else if ( CtClass.byteType.equals( persistentField.getType() )) {
return new PrimitiveAttributeTypeDescriptor( inheritanceMetadata, Byte.TYPE );
}
else if ( persistentField.getType() == CtClass.charType ) {
return new PrimitiveAttributeTypeDescriptor( Character.TYPE );
else if ( CtClass.charType.equals( persistentField.getType() ) ) {
return new PrimitiveAttributeTypeDescriptor( inheritanceMetadata, Character.TYPE );
}
else if ( persistentField.getType() == CtClass.shortType ) {
return new PrimitiveAttributeTypeDescriptor( Short.TYPE );
else if ( CtClass.shortType.equals( persistentField.getType() ) ) {
return new PrimitiveAttributeTypeDescriptor( inheritanceMetadata, Short.TYPE );
}
else if ( persistentField.getType() == CtClass.intType ) {
return new PrimitiveAttributeTypeDescriptor( Integer.TYPE );
else if ( CtClass.intType.equals( persistentField.getType() ) ) {
return new PrimitiveAttributeTypeDescriptor( inheritanceMetadata, Integer.TYPE );
}
else if ( persistentField.getType() == CtClass.longType ) {
return new PrimitiveAttributeTypeDescriptor( Long.TYPE );
else if ( CtClass.longType.equals( persistentField.getType() ) ) {
return new PrimitiveAttributeTypeDescriptor( inheritanceMetadata, Long.TYPE );
}
else if ( persistentField.getType() == CtClass.doubleType ) {
return new PrimitiveAttributeTypeDescriptor( Double.TYPE );
else if ( CtClass.doubleType.equals( persistentField.getType() ) ) {
return new PrimitiveAttributeTypeDescriptor( inheritanceMetadata, Double.TYPE );
}
else if ( persistentField.getType() == CtClass.floatType ) {
return new PrimitiveAttributeTypeDescriptor( Float.TYPE );
else if ( CtClass.floatType.equals( persistentField.getType() ) ) {
return new PrimitiveAttributeTypeDescriptor( inheritanceMetadata, Float.TYPE );
}
else {
return new ObjectAttributeTypeDescriptor( persistentField.getType() );
return new ObjectAttributeTypeDescriptor( inheritanceMetadata, persistentField.getType() );
}
}

Expand All @@ -114,26 +129,53 @@ private static class ObjectAttributeTypeDescriptor extends AttributeTypeDescript

private final String type;

private ObjectAttributeTypeDescriptor(CtClass concreteType) {
private ObjectAttributeTypeDescriptor(InheritanceMetadata inheritanceMetadata, CtClass concreteType) {
super( inheritanceMetadata );
this.type = concreteType.getName();
}

@Override
public String buildReadInterceptionBodyFragment(String fieldName) {
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 );
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) {
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 );
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 );
}
}
}

Expand All @@ -144,32 +186,93 @@ private static class PrimitiveAttributeTypeDescriptor extends AttributeTypeDescr

private final String type;

private PrimitiveAttributeTypeDescriptor(Class<?> primitiveType) {
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) {
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 );
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) {
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
);
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;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@
*/
package org.hibernate.bytecode.enhance.internal;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
Expand All @@ -17,6 +19,7 @@
import javassist.CtField;
import javassist.Modifier;

import javassist.NotFoundException;
import org.hibernate.bytecode.enhance.internal.tracker.DirtyTracker;
import org.hibernate.bytecode.enhance.internal.tracker.SimpleCollectionTracker;
import org.hibernate.bytecode.enhance.internal.tracker.SimpleFieldTracker;
Expand Down Expand Up @@ -206,7 +209,7 @@ private void createDirtyTrackerMethods(CtClass managedCtClass) {
}

private List<CtField> collectCollectionFields(CtClass managedCtClass) {
final List<CtField> collectionList = new LinkedList<CtField>();
List<CtField> collectionList = new ArrayList<CtField>();

for ( CtField ctField : managedCtClass.getDeclaredFields() ) {
// skip static fields and skip fields added by enhancement
Expand All @@ -222,19 +225,40 @@ private List<CtField> collectCollectionFields(CtClass managedCtClass) {
}

// HHH-10646 Add fields inherited from @MappedSuperclass
for ( CtField ctField : managedCtClass.getDeclaredFields() ) {
if ( !enhancementContext.isMappedSuperclassClass( ctField.getDeclaringClass() ) || Modifier.isStatic( ctField.getModifiers() ) ) {
continue;
// HHH-10981 There is no need to do it for @MappedSuperclass
if ( !enhancementContext.isMappedSuperclassClass( managedCtClass ) ) {
collectionList.addAll( collectInheritCollectionFields( managedCtClass ) );
}

return collectionList;
}

private Collection<CtField> collectInheritCollectionFields(CtClass managedCtClass) {
if ( managedCtClass == null || Object.class.getName().equals( managedCtClass.getName() ) ) {
return Collections.emptyList();
}
try {
CtClass managedCtSuperclass = managedCtClass.getSuperclass();

if ( !enhancementContext.isMappedSuperclassClass( managedCtSuperclass ) ) {
return collectInheritCollectionFields( managedCtSuperclass );
}
if ( enhancementContext.isPersistentField( ctField ) ) {
if ( PersistentAttributesHelper.isAssignable( ctField, Collection.class.getName() ) ||
PersistentAttributesHelper.isAssignable( ctField, Map.class.getName() ) ) {
collectionList.add( ctField );
List<CtField> collectionList = new ArrayList<CtField>();

for ( CtField ctField : managedCtSuperclass.getDeclaredFields() ) {
if ( !Modifier.isStatic( ctField.getModifiers() ) && enhancementContext.isPersistentField( ctField ) ) {
if ( PersistentAttributesHelper.isAssignable( ctField, Collection.class.getName() ) ||
PersistentAttributesHelper.isAssignable( ctField, Map.class.getName() ) ) {
collectionList.add( ctField );
}
}
}
collectionList.addAll( collectInheritCollectionFields( managedCtSuperclass ) );
return collectionList;
}
catch ( NotFoundException nfe ) {
return Collections.emptyList();
}

return collectionList;
}

private void createCollectionDirtyCheckMethod(CtClass managedCtClass) {
Expand Down
Loading

0 comments on commit e41867b

Please sign in to comment.