Skip to content

Commit

Permalink
Take into account non-public fields when enhancing Hibernate ORM enti…
Browse files Browse the repository at this point in the history
…ty field access
  • Loading branch information
yrodiere committed Apr 25, 2023
1 parent 6eb09e9 commit 8c10a3b
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 26 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -289,14 +289,14 @@ protected void processEntities(CombinedIndexBuildItem index,
}

private void replaceFieldAccesses(BuildProducer<BytecodeTransformerBuildItem> transformers, MetamodelInfo modelInfo) {
Set<String> entitiesWithPublicFields = modelInfo.getEntitiesWithPublicFields();
if (entitiesWithPublicFields.isEmpty()) {
// There are no public fields to be accessed in the first place.
Set<String> entitiesWithExternallyAccessibleFields = modelInfo.getEntitiesWithExternallyAccessibleFields();
if (entitiesWithExternallyAccessibleFields.isEmpty()) {
// There are no fields to be accessed in the first place.
return;
}

Set<String> entityClassNamesInternal = new HashSet<>();
for (String entityClassName : entitiesWithPublicFields) {
for (String entityClassName : entitiesWithExternallyAccessibleFields) {
entityClassNamesInternal.add(entityClassName.replace(".", "/"));
}

Expand All @@ -323,10 +323,11 @@ private EntityModel createEntityModel(ClassInfo classInfo) {
EntityModel entityModel = new EntityModel(classInfo);
for (FieldInfo fieldInfo : classInfo.fields()) {
String name = fieldInfo.name();
if (Modifier.isPublic(fieldInfo.flags())
var visibility = EntityField.Visibility.get(fieldInfo.flags());
if (EntityField.Visibility.PUBLIC.equals(visibility)
&& !Modifier.isStatic(fieldInfo.flags())
&& !fieldInfo.hasAnnotation(BSON_IGNORE)) {
entityModel.addField(new EntityField(name, DescriptorUtils.typeToString(fieldInfo.type())));
entityModel.addField(new EntityField(name, DescriptorUtils.typeToString(fieldInfo.type()), visibility));
}
}
return entityModel;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.quarkus.panache.common.deployment;

import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
Expand All @@ -10,19 +11,22 @@

import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;

import io.quarkus.deployment.bean.JavaBeanUtil;

public class EntityField {

public final String name;
public final String descriptor;
public final Visibility visibility;
public String signature;
public final Set<EntityFieldAnnotation> annotations = new HashSet<>(2);

public EntityField(String name, String descriptor) {
public EntityField(String name, String descriptor, Visibility visibility) {
this.name = name;
this.descriptor = descriptor;
this.visibility = visibility;
}

public String getGetterName() {
Expand All @@ -42,6 +46,31 @@ public boolean hasAnnotation(String descriptor) {
return false;
}

public enum Visibility {
PUBLIC(Opcodes.ACC_PUBLIC),
PROTECTED(Opcodes.ACC_PROTECTED),
PACKAGE_PRIVATE(0),
PRIVATE(Opcodes.ACC_PRIVATE);

public final int accessOpCode;

Visibility(int accessOpCode) {
this.accessOpCode = accessOpCode;
}

public static Visibility get(int flags) {
if (Modifier.isPublic(flags)) {
return PUBLIC;
} else if (Modifier.isPrivate(flags)) {
return PRIVATE;
} else if (Modifier.isProtected(flags)) {
return PROTECTED;
} else {
return PACKAGE_PRIVATE;
}
}
}

public static class EntityFieldAnnotation {
public final String descriptor;
public final Map<String, Object> attributes = new HashMap<>(2);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public void addEntityModel(EntityModel entityModel) {
entities.put(entityModel.name, entityModel);
}

public Set<String> getEntitiesWithPublicFields() {
public Set<String> getEntitiesWithExternallyAccessibleFields() {
return entities.entrySet().stream()
.filter(e -> {
EntityModel value = e.getValue();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,11 +68,11 @@ public FieldVisitor visitField(int access, String name, String descriptor, Strin
//so any errors are visible immediately, rather than data just being lost

FieldVisitor superVisitor;
if (name.equals("id")) {
superVisitor = super.visitField(access, name, descriptor, signature, value);
} else {
if (!name.equals("id") && Modifier.isPublic(access)) {
superVisitor = super.visitField((access | Modifier.PROTECTED) & ~(Modifier.PRIVATE | Modifier.PUBLIC),
name, descriptor, signature, value);
} else {
superVisitor = super.visitField(access, name, descriptor, signature, value);
}
entityField.signature = signature;
// if we have a mapped field, let's add some annotations
Expand Down Expand Up @@ -126,7 +126,7 @@ private void generateAccessors() {
String getterName = field.getGetterName();
String getterDescriptor = "()" + field.descriptor;
if (!userMethods.contains(getterName + "/" + getterDescriptor)) {
MethodVisitor mv = super.visitMethod(Opcodes.ACC_PUBLIC,
MethodVisitor mv = super.visitMethod(field.visibility.accessOpCode,
getterName, getterDescriptor, field.signature == null ? null : "()" + field.signature, null);
mv.visitCode();
mv.visitIntInsn(Opcodes.ALOAD, 0);
Expand Down Expand Up @@ -159,7 +159,7 @@ private void generateAccessors() {
String setterName = field.getSetterName();
String setterDescriptor = "(" + field.descriptor + ")V";
if (!userMethods.contains(setterName + "/" + setterDescriptor)) {
MethodVisitor mv = super.visitMethod(Opcodes.ACC_PUBLIC,
MethodVisitor mv = super.visitMethod(field.visibility.accessOpCode,
setterName, setterDescriptor, field.signature == null ? null : "(" + field.signature + ")V", null);
mv.visitCode();
mv.visitIntInsn(Opcodes.ALOAD, 0);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,15 +68,15 @@ void findEntityClasses(CombinedIndexBuildItem index,
// Share the metamodel for use in replaceFieldAccesses
modelInfoBuildItem.produce(new HibernateMetamodelForFieldAccessBuildItem(modelInfo));

Set<String> entitiesWithPublicFields = modelInfo.getEntitiesWithPublicFields();
if (entitiesWithPublicFields.isEmpty()) {
// There are no public fields to be accessed in the first place.
Set<String> entitiesWithExternallyAccessibleFields = modelInfo.getEntitiesWithExternallyAccessibleFields();
if (entitiesWithExternallyAccessibleFields.isEmpty()) {
// There are no fields to be accessed in the first place.
return;
}

// Share with other extensions that we will generate accessors for some classes
fieldAccessEnhancedEntityClasses
.produce(new PanacheEntityClassesBuildItem(entitiesWithPublicFields));
.produce(new PanacheEntityClassesBuildItem(entitiesWithExternallyAccessibleFields));
}

@BuildStep
Expand All @@ -91,23 +91,23 @@ void replaceFieldAccesses(CombinedIndexBuildItem index,
}

MetamodelInfo modelInfo = modelInfoBuildItem.get().getMetamodelInfo();
Set<String> entitiesWithPublicFields = modelInfo.getEntitiesWithPublicFields();
if (entitiesWithPublicFields.isEmpty()) {
// There are no public fields to be accessed in the first place.
Set<String> entitiesWithExternallyAccessibleFields = modelInfo.getEntitiesWithExternallyAccessibleFields();
if (entitiesWithExternallyAccessibleFields.isEmpty()) {
// There are no fields to be accessed in the first place.
return;
}

// Generate accessors for public fields in entities, mapped superclasses
// Generate accessors for externally accessible fields in entities, mapped superclasses
// (and embeddables, see where we build modelInfo above).
PanacheJpaEntityAccessorsEnhancer entityAccessorsEnhancer = new PanacheJpaEntityAccessorsEnhancer(index.getIndex(),
modelInfo);
for (String entityClassName : entitiesWithPublicFields) {
for (String entityClassName : entitiesWithExternallyAccessibleFields) {
transformers.produce(new BytecodeTransformerBuildItem(true, entityClassName, entityAccessorsEnhancer));
}

// Replace field access in application code with calls to accessors
Set<String> entityClassNamesInternal = new HashSet<>();
for (String entityClassName : entitiesWithPublicFields) {
for (String entityClassName : entitiesWithExternallyAccessibleFields) {
entityClassNamesInternal.add(entityClassName.replace(".", "/"));
}

Expand Down Expand Up @@ -146,10 +146,10 @@ private EntityModel createEntityModel(ClassInfo classInfo) {
EntityModel entityModel = new EntityModel(classInfo);
for (FieldInfo fieldInfo : classInfo.fields()) {
String name = fieldInfo.name();
if (Modifier.isPublic(fieldInfo.flags())
&& !Modifier.isStatic(fieldInfo.flags())
if (!Modifier.isStatic(fieldInfo.flags())
&& !fieldInfo.hasAnnotation(DOTNAME_TRANSIENT)) {
entityModel.addField(new EntityField(name, DescriptorUtils.typeToString(fieldInfo.type())));
entityModel.addField(new EntityField(name, DescriptorUtils.typeToString(fieldInfo.type()),
EntityField.Visibility.get(fieldInfo.flags())));
}
}
return entityModel;
Expand Down

0 comments on commit 8c10a3b

Please sign in to comment.