This is an automated email from the ASF dual-hosted git repository. struberg pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/openjpa.git
commit 1a287b267f86079aa79348e9d24f93469522d07a Author: Mark Struberg <strub...@apache.org> AuthorDate: Mon Jun 12 20:20:20 2023 +0200 OPENJPA-2911 fix pcClearFields for mixed access subclassing --- .../org/apache/openjpa/enhance/PCEnhancer.java | 5 +- .../org/apache/openjpa/meta/ClassMetaData.java | 28 ++++----- .../openjpa/enhance/TestSubclassValidator.java | 20 ------- .../enhance/TestMixedAccessSubclassing.java | 69 ++++++++++++++++++++++ .../enhance/common/apps/MixedAccessPerson.java | 67 +++++++++++++++++++++ .../openjpa/persistence/meta/TestMetamodel.java | 48 +++++++-------- 6 files changed, 175 insertions(+), 62 deletions(-) diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/PCEnhancer.java b/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/PCEnhancer.java index ff7435884..beda0f2bc 100644 --- a/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/PCEnhancer.java +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/PCEnhancer.java @@ -5189,10 +5189,7 @@ public class PCEnhancer { // just do a subclass approach instead. But this is not a good option, // since it would sacrifice lazy loading and efficient dirty tracking. if (getRedefine() || isFieldAccess(fmd)) { - instructions.add(new FieldInsnNode(Opcodes.PUTFIELD, - Type.getInternalName(fmd.getDeclaringType()), - fmd.getName(), - Type.getDescriptor(fmd.getDeclaredType()))); + putfield(instructions, fmd.getDeclaringType(), fmd.getName(), fmd.getDeclaredType()); } else if (getCreateSubclass()) { // property access, and we're not redefining. invoke the diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/meta/ClassMetaData.java b/openjpa-kernel/src/main/java/org/apache/openjpa/meta/ClassMetaData.java index 08483aa2c..655a3cf39 100644 --- a/openjpa-kernel/src/main/java/org/apache/openjpa/meta/ClassMetaData.java +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/meta/ClassMetaData.java @@ -717,27 +717,27 @@ public class ClassMetaData * Sets the access type. */ public void setAccessType(int type) { - if (type == _accessType || type == AccessCode.UNKNOWN) - return; - if (!AccessCode.isValidClassCode(type)) { + if (type == _accessType || type == AccessCode.UNKNOWN) + return; + if (!AccessCode.isValidClassCode(type)) { throw new IllegalArgumentException(_loc.get("access-type-invalid", - this, AccessCode.toClassString(type)).getMessage()); - } - if (_accessType != AccessCode.UNKNOWN) { // changing access type - _repos.getLog().trace(_loc.get("access-type-change", - this, AccessCode.toClassString(type), - AccessCode.toClassString(_accessType)).getMessage()); - } + this, AccessCode.toClassString(type)).getMessage()); + } + if (_accessType != AccessCode.UNKNOWN) { // changing access type + _repos.getLog().trace(_loc.get("access-type-change", + this, AccessCode.toClassString(type), + AccessCode.toClassString(_accessType)).getMessage()); + } _accessType = type; } /** - * Asserts the the given field (which must belong to this receiver) + * Asserts the given field (which must belong to this receiver) * can be set to the given access code. If the field code is allowed, - * it may have the side-effect of changing the access code of this receiver. + * it may have the side effect of changing the access code of this receiver. */ void mergeFieldAccess(FieldMetaData fmd, int fCode) { - setAccessType(AccessCode.mergeFieldCode(this, fmd, fCode)); + setAccessType(AccessCode.mergeFieldCode(this, fmd, fCode)); } /** @@ -751,7 +751,7 @@ public class ClassMetaData * Affirms if attributes of this class use mixed access types. */ public boolean isMixedAccess() { - return AccessCode.isMixed(_accessType); + return AccessCode.isMixed(_accessType); } /** diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/enhance/TestSubclassValidator.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/enhance/TestSubclassValidator.java index 04d43ca1c..0e774c015 100644 --- a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/enhance/TestSubclassValidator.java +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/enhance/TestSubclassValidator.java @@ -58,26 +58,6 @@ public class TestSubclassValidator extends SingleEMFTestCase { repos.setSourceMode(MetaDataModes.MODE_META); final Log log = conf.getLog(OpenJPAConfiguration.LOG_ENHANCE); -/* - - { - final BCClass bcClass = project.loadClass(Department.class.getName(), tempCl); - final ClassMetaData meta = repos.getMetaData(tempCl.loadClass(Department.class.getName()), tempCl, false); - PCSubclassValidator subclassValidator = new PCSubclassValidator(meta, bcClass, log, false); - subclassValidator.assertCanSubclass(); - } - - try { - final BCClass bcClass = project.loadClass(RuntimeTest2.class.getName(), tempCl); - final ClassMetaData meta = repos.getMetaData(tempCl.loadClass(RuntimeTest2.class.getName()), tempCl, false); - PCSubclassValidator subclassValidator = new PCSubclassValidator(meta, bcClass, log, true); - subclassValidator.assertCanSubclass(); - fail("RuntimeTest2 validation should fail"); - } - catch (UserException ue) { - // all fine - } -*/ { ClassNode classNode = AsmHelper.readClassNode(EnhanceableGetterEntity.class.getClassLoader(), EnhanceableGetterEntity.class.getName()); diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/enhance/TestMixedAccessSubclassing.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/enhance/TestMixedAccessSubclassing.java new file mode 100644 index 000000000..c59dfbc5c --- /dev/null +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/enhance/TestMixedAccessSubclassing.java @@ -0,0 +1,69 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.openjpa.persistence.enhance; + +import org.apache.openjpa.persistence.enhance.common.apps.MixedAccessPerson; +import org.apache.openjpa.persistence.test.SingleEMTestCase; +import org.junit.Test; + +/** + * Test subclass enhancement on the fly with mixed access strategy + * + * @author <a href="mailto:strub...@apache.org">Mark Struberg</a> + */ +public class TestMixedAccessSubclassing extends SingleEMTestCase { + + @Override + public void setUp() { + super.setUp( + "openjpa.RuntimeUnenhancedClasses", "supported", + "openjpa.DynamicEnhancementAgent", "false", + MixedAccessPerson.class); + } + + @Test + public void testDynamicEnhancement() { + int pk = -1; + { + em.getTransaction().begin(); + // step 1: create the person + MixedAccessPerson p = new MixedAccessPerson(); + p.setFirstName("Han"); + p.setLastName("Solo"); + assertEquals("changed_Solo", p.getLastName()); + em.persist(p); + em.flush(); + pk = p.getId(); + em.clear(); + em.getTransaction().commit(); + } + + { + em.getTransaction().begin(); + // step 2: read back the person + MixedAccessPerson p2 = em.find(MixedAccessPerson.class, pk); + assertNotNull(p2); + + assertEquals(pk, p2.getId()); + assertEquals("Han", p2.getFirstName()); + + // since we use property access the setter will get invoked again -> 2x changed_ + assertEquals("changed_changed_Solo", p2.getLastName()); + em.getTransaction().commit(); + } + } +} diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/enhance/common/apps/MixedAccessPerson.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/enhance/common/apps/MixedAccessPerson.java new file mode 100644 index 000000000..64089ba34 --- /dev/null +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/enhance/common/apps/MixedAccessPerson.java @@ -0,0 +1,67 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.openjpa.persistence.enhance.common.apps; + +import jakarta.persistence.Access; +import jakarta.persistence.AccessType; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.Id; + +/** + * Entity to test subclass enhancing with mixed access + * Note that this class will not be enhanced during the build! + * + * @author <a href="mailto:strub...@apache.org">Mark Struberg</a> + */ +@Entity +@Access(AccessType.FIELD) +public class MixedAccessPerson { + + @Id + @GeneratedValue + private int id; + + private String firstName; + + private String internalLastName; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + @Access(AccessType.PROPERTY) + public String getLastName() { + return internalLastName; + } + + public void setLastName(String lastName) { + this.internalLastName = lastName != null ? "changed_" + lastName : null; + } +} diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/meta/TestMetamodel.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/meta/TestMetamodel.java index 464f8731c..504a853b0 100644 --- a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/meta/TestMetamodel.java +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/meta/TestMetamodel.java @@ -60,24 +60,24 @@ public class TestMetamodel extends SingleEMFTestCase { @Override public void setUp() { if (model == null) { - super.setUp( - "openjpa.RuntimeUnenhancedClasses", "unsupported", - "openjpa.DynamicEnhancementAgent", "false", - ImplicitFieldAccessMappedSuperclass.class, - ImplicitFieldAccessBase.class, - ImplicitFieldAccessSubclass.class, - ExplicitFieldAccess.class, - ExplicitPropertyAccess.class, - Embed0.class, - Embed1.class, - OneOneParent.class, - OneOneChild.class, - Book.class, - Library.class, - Page.class, - Address.class, - Geocode.class); - emf.createEntityManager(); + super.setUp( + "openjpa.RuntimeUnenhancedClasses", "unsupported", + "openjpa.DynamicEnhancementAgent", "false", + ImplicitFieldAccessMappedSuperclass.class, + ImplicitFieldAccessBase.class, + ImplicitFieldAccessSubclass.class, + ExplicitFieldAccess.class, + ExplicitPropertyAccess.class, + Embed0.class, + Embed1.class, + OneOneParent.class, + OneOneChild.class, + Book.class, + Library.class, + Page.class, + Address.class, + Geocode.class); + emf.createEntityManager(); model = (MetamodelImpl)emf.getMetamodel(); } } @@ -109,11 +109,11 @@ public class TestMetamodel extends SingleEMFTestCase { } public void testDomainClassCategorizedInPersistentCategory() { - assertCategory(PersistenceType.MAPPED_SUPERCLASS, ImplicitFieldAccessMappedSuperclass.class); - assertCategory(PersistenceType.ENTITY, ImplicitFieldAccessBase.class); - assertCategory(PersistenceType.ENTITY, ImplicitFieldAccessSubclass.class); - assertCategory(PersistenceType.EMBEDDABLE, Embed0.class); - assertCategory(PersistenceType.EMBEDDABLE, Embed1.class); + assertCategory(PersistenceType.MAPPED_SUPERCLASS, ImplicitFieldAccessMappedSuperclass.class); + assertCategory(PersistenceType.ENTITY, ImplicitFieldAccessBase.class); + assertCategory(PersistenceType.ENTITY, ImplicitFieldAccessSubclass.class); + assertCategory(PersistenceType.EMBEDDABLE, Embed0.class); + assertCategory(PersistenceType.EMBEDDABLE, Embed1.class); assertNotNull(model.entity(ImplicitFieldAccessBase.class)); assertNotNull(model.entity(ImplicitFieldAccessSubclass.class)); @@ -401,7 +401,7 @@ public class TestMetamodel extends SingleEMFTestCase { } void assertCategory(PersistenceType category, Class<?> cls) { - assertEquals(cls.toString(), category, categorize(cls)); + assertEquals(cls.toString(), category, categorize(cls)); } Field getStaticField(Class<?> cls, String name) {