From 036658a7f359126a0210a3d1f6039177d05c6812 Mon Sep 17 00:00:00 2001 From: Will Dazey Date: Fri, 24 Sep 2021 21:44:33 -0500 Subject: [PATCH] Bug 412391: Add support for hidden mappedsuperclass attributes Signed-off-by: Will Dazey --- .../jpa/test/weave/TestWeaving.java | 87 +++++++++++++++++++ .../test/weave/model/WeavedAbstractMS.java | 36 ++++++++ .../jpa/test/weave/model/WeavedEntityA.java | 32 +++++++ .../jpa/weaving/TransformerFactory.java | 65 +++++++++----- 4 files changed, 198 insertions(+), 22 deletions(-) create mode 100644 jpa/eclipselink.jpa.test.jse/src/it/java/org/eclipse/persistence/jpa/test/weave/TestWeaving.java create mode 100644 jpa/eclipselink.jpa.test.jse/src/it/java/org/eclipse/persistence/jpa/test/weave/model/WeavedAbstractMS.java create mode 100644 jpa/eclipselink.jpa.test.jse/src/it/java/org/eclipse/persistence/jpa/test/weave/model/WeavedEntityA.java diff --git a/jpa/eclipselink.jpa.test.jse/src/it/java/org/eclipse/persistence/jpa/test/weave/TestWeaving.java b/jpa/eclipselink.jpa.test.jse/src/it/java/org/eclipse/persistence/jpa/test/weave/TestWeaving.java new file mode 100644 index 00000000000..ce16868d447 --- /dev/null +++ b/jpa/eclipselink.jpa.test.jse/src/it/java/org/eclipse/persistence/jpa/test/weave/TestWeaving.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2021 Oracle, and/or affiliates. All rights reserved. + * Copyright (c) 2021 IBM Corporation. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, + * or the Eclipse Distribution License v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +// Contributors: +// IBM - Bug 412391: Add support for weaving hidden variables +package org.eclipse.persistence.jpa.test.weave; + +import jakarta.persistence.EntityManager; +import jakarta.persistence.EntityManagerFactory; + +import org.eclipse.persistence.jpa.test.framework.DDLGen; +import org.eclipse.persistence.jpa.test.framework.Emf; +import org.eclipse.persistence.jpa.test.framework.EmfRunner; +import org.eclipse.persistence.jpa.test.framework.Property; +import org.eclipse.persistence.jpa.test.weave.model.WeavedAbstractMS; +import org.eclipse.persistence.jpa.test.weave.model.WeavedEntityA; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(EmfRunner.class) +public class TestWeaving { + + @Emf(createTables = DDLGen.DROP_CREATE, + classes = { WeavedAbstractMS.class, WeavedEntityA.class }, + properties = { @Property(name = "eclipselink.cache.shared.default", value = "false") }) + private EntityManagerFactory emf; + + private static boolean POPULATED = false; + + @Test + public void testHiddenAttribute() throws Exception { + if (emf == null) + return; + + if(!POPULATED) + populate(); + + EntityManager em = emf.createEntityManager(); + try { + final WeavedEntityA e1 = em.find(WeavedEntityA.class, 123l); + + Assert.assertNotNull(e1); + Assert.assertNotNull(e1.getHiddenAttribute()); + } catch (Exception e) { + e.printStackTrace(); + throw e; + } finally { + if (em != null) { + if (em.getTransaction().isActive()) { + em.getTransaction().rollback(); + } + em.close(); + } + } + } + + private void populate() { + EntityManager em = emf.createEntityManager(); + try { + em.getTransaction().begin(); + + WeavedEntityA tbl1 = new WeavedEntityA(); + tbl1.setId(123l); + tbl1.setHiddenAttribute((short) 1); + em.persist(tbl1); + + em.getTransaction().commit(); + + POPULATED = true; + } finally { + if(em.isOpen()) { + em.clear(); + em.close(); + } + } + } +} diff --git a/jpa/eclipselink.jpa.test.jse/src/it/java/org/eclipse/persistence/jpa/test/weave/model/WeavedAbstractMS.java b/jpa/eclipselink.jpa.test.jse/src/it/java/org/eclipse/persistence/jpa/test/weave/model/WeavedAbstractMS.java new file mode 100644 index 00000000000..89966b66b19 --- /dev/null +++ b/jpa/eclipselink.jpa.test.jse/src/it/java/org/eclipse/persistence/jpa/test/weave/model/WeavedAbstractMS.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2021 Oracle, and/or affiliates. All rights reserved. + * Copyright (c) 2021 IBM Corporation. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, + * or the Eclipse Distribution License v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +// Contributors: +// IBM - Bug 412391: Add support for weaving hidden variables +package org.eclipse.persistence.jpa.test.weave.model; + +import jakarta.persistence.MappedSuperclass; + +@MappedSuperclass +public abstract class WeavedAbstractMS { + private String parentOnlyAttribute; + private Short hiddenAttribute; + + public String getParentOnlyAttribute() { + return parentOnlyAttribute; + } + public void setParentOnlyAttribute(String parentOnlyAttribute) { + this.parentOnlyAttribute = parentOnlyAttribute; + } + public Short getHiddenAttribute() { + return hiddenAttribute; + } + public void setHiddenAttribute(Short hiddenAttribute) { + this.hiddenAttribute = hiddenAttribute; + } +} \ No newline at end of file diff --git a/jpa/eclipselink.jpa.test.jse/src/it/java/org/eclipse/persistence/jpa/test/weave/model/WeavedEntityA.java b/jpa/eclipselink.jpa.test.jse/src/it/java/org/eclipse/persistence/jpa/test/weave/model/WeavedEntityA.java new file mode 100644 index 00000000000..d24b06171a7 --- /dev/null +++ b/jpa/eclipselink.jpa.test.jse/src/it/java/org/eclipse/persistence/jpa/test/weave/model/WeavedEntityA.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2021 Oracle, and/or affiliates. All rights reserved. + * Copyright (c) 2021 IBM Corporation. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, + * or the Eclipse Distribution License v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +// Contributors: +// IBM - Bug 412391: Add support for weaving hidden variables +package org.eclipse.persistence.jpa.test.weave.model; + +import jakarta.persistence.Entity; +import jakarta.persistence.Id; + +@Entity +public class WeavedEntityA extends WeavedAbstractMS { + + @Id private long id; + private Short hiddenAttribute; + + public long getId() { + return id; + } + public void setId(long id) { + this.id = id; + } +} diff --git a/jpa/org.eclipse.persistence.jpa/src/main/java/org/eclipse/persistence/internal/jpa/weaving/TransformerFactory.java b/jpa/org.eclipse.persistence.jpa/src/main/java/org/eclipse/persistence/internal/jpa/weaving/TransformerFactory.java index 0b626aa575c..6ac60b53979 100644 --- a/jpa/org.eclipse.persistence.jpa/src/main/java/org/eclipse/persistence/internal/jpa/weaving/TransformerFactory.java +++ b/jpa/org.eclipse.persistence.jpa/src/main/java/org/eclipse/persistence/internal/jpa/weaving/TransformerFactory.java @@ -1,5 +1,6 @@ /* - * Copyright (c) 1998, 2020 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2021 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021 IBM Corporation. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -111,7 +112,7 @@ public TransformerFactory(Session session, Collection entityClass * We assume that if a mapping exists, the attribute must either be mapped from the owning * class or from a superclass. */ - public void addClassDetailsForMappedSuperClasses(MetadataClass clz, ClassDescriptor initialDescriptor, ClassDetails classDetails, Map classDetailsMap, List unMappedAttributes, boolean weaveChangeTracking){ + public void addClassDetailsForMappedSuperClasses(MetadataClass clz, ClassDescriptor initialDescriptor, ClassDetails classDetails, Map classDetailsMap, List unMappedAttributes, boolean weaveChangeTracking){ MetadataClass superClz = clz.getSuperclass(); if (superClz == null || superClz.isObject()){ return; @@ -125,9 +126,29 @@ public void addClassDetailsForMappedSuperClasses(MetadataClass clz, ClassDescrip } } + // If the superclass declares more mappings than there are unmapped mappings still to process, this superclass has shadowed attributes + if(mappedSuperclassDescriptor != null && unMappedAttributes.size() < mappedSuperclassDescriptor.getMappings().size()) { + List hiddenMappings = new ArrayList(); + for(DatabaseMapping mapping : mappedSuperclassDescriptor.getMappings()) { + boolean contains = false; + String name = mapping.getAttributeName(); + for(DatabaseMapping newmapping : unMappedAttributes) { + if(name.equals(newmapping.getAttributeName())) { + contains = true; + break; + } + } + // If the super has a mapping that wasn't processed by the subclasses, add it to be processed + if(!contains) { + hiddenMappings.add(mapping); + } + } + unMappedAttributes.addAll(hiddenMappings); + } + boolean weaveValueHolders = canWeaveValueHolders(superClz, unMappedAttributes); - List stillUnMappedMappings = null; + List stillUnMappedMappings = null; ClassDetails superClassDetails = createClassDetails(superClz, weaveValueHolders, weaveChangeTracking, weaveFetchGroups, weaveInternal, weaveRest); superClassDetails.setIsMappedSuperClass(true); @@ -193,7 +214,7 @@ public void buildClassDetailsAndModifyProject() { classDetails.getVirtualAccessMethods().addAll(descriptor.getVirtualAttributeMethods()); - List unMappedAttributes = storeAttributeMappings(metaClass, classDetails, descriptor.getMappings(), weaveValueHoldersForClass); + List unMappedAttributes = storeAttributeMappings(metaClass, classDetails, descriptor.getMappings(), weaveValueHoldersForClass); classDetailsMap.put(classDetails.getClassName() ,classDetails); classDetails.setShouldWeaveConstructorOptimization((classDetails.getDescribedClass().getFields().size() - (descriptor.getMappings().size() - unMappedAttributes.size()))<=0); @@ -204,8 +225,8 @@ public void buildClassDetailsAndModifyProject() { } // hookup superClassDetails - for (Iterator i = classDetailsMap.values().iterator(); i.hasNext();) { - ClassDetails classDetails = (ClassDetails)i.next(); + for (Iterator i = classDetailsMap.values().iterator(); i.hasNext();) { + ClassDetails classDetails = i.next(); ClassDetails superClassDetails = classDetailsMap.get(classDetails.getSuperClassName()); if (superClassDetails == null) { ClassDescriptor descriptor = findDescriptor(session.getProject(), classDetails.getDescribedClass().getName()); @@ -220,8 +241,8 @@ public void buildClassDetailsAndModifyProject() { // Fix weaveChangeTracking based on superclasses, // we should only weave change tracking if our whole hierarchy can. - for (Iterator i = classDetailsMap.values().iterator(); i.hasNext();) { - ClassDetails classDetails = (ClassDetails)i.next(); + for (Iterator i = classDetailsMap.values().iterator(); i.hasNext();) { + ClassDetails classDetails = i.next(); classDetails.setShouldWeaveChangeTracking(classDetails.canWeaveChangeTracking()); } } @@ -252,10 +273,10 @@ protected boolean canChangeTrackingBeEnabled(ClassDescriptor descriptor, Metadat return canWeaveChangeTracking; } - protected boolean wasChangeTrackingAlreadyWeaved(Class clz){ - Class[] interfaces = clz.getInterfaces(); + protected boolean wasChangeTrackingAlreadyWeaved(Class clz){ + Class[] interfaces = clz.getInterfaces(); for (int i = 0; i < interfaces.length; i++) { - Class c = interfaces[i]; + Class c = interfaces[i]; if (c.getName().equals(PersistenceWeavedChangeTracking.class.getName())){ return true; } @@ -266,11 +287,11 @@ protected boolean wasChangeTrackingAlreadyWeaved(Class clz){ /** * Determine if value holders are required to be weaved into the class. */ - protected boolean canWeaveValueHolders(MetadataClass clz, List mappings) { + protected boolean canWeaveValueHolders(MetadataClass clz, List mappings) { // we intend to change to fetch=LAZY 1:1 attributes to ValueHolders boolean weaveValueHolders = false; - for (Iterator iterator = mappings.iterator(); iterator.hasNext();) { - DatabaseMapping mapping = (DatabaseMapping)iterator.next(); + for (Iterator iterator = mappings.iterator(); iterator.hasNext();) { + DatabaseMapping mapping = iterator.next(); String attributeName = mapping.getAttributeName(); if (mapping.isForeignReferenceMapping()) { ForeignReferenceMapping foreignReferenceMapping = (ForeignReferenceMapping)mapping; @@ -298,7 +319,7 @@ private ClassDetails createClassDetails(MetadataClass metadataClass, boolean wea classDetails.setShouldWeaveFetchGroups(weaveFetchGroups); classDetails.setShouldWeaveInternal(weaveInternal); classDetails.setShouldWeaveREST(weaveRest); - MetadataMethod method = metadataClass.getMethod("clone", new ArrayList(), false); + MetadataMethod method = metadataClass.getMethod("clone", new ArrayList(), false); classDetails.setImplementsCloneMethod(method != null); return classDetails; } @@ -309,9 +330,9 @@ private ClassDetails createClassDetails(MetadataClass metadataClass, boolean wea * This avoids having to construct a project by class facilitating weaving */ protected ClassDescriptor findDescriptor(Project project, String className){ - Iterator iterator = project.getOrderedDescriptors().iterator(); + Iterator iterator = project.getOrderedDescriptors().iterator(); while (iterator.hasNext()){ - ClassDescriptor descriptor = (ClassDescriptor)iterator.next(); + ClassDescriptor descriptor = iterator.next(); if (descriptor.getJavaClassName().equals(className)){ return descriptor; } @@ -344,7 +365,7 @@ private MetadataClass getAttributeTypeFromClass(MetadataClass metadataClass, Str if (mapping.isAbstractDirectMapping() && mapping.getAttributeAccessor().isVirtualAttributeAccessor()){ return metadataClass.getMetadataClass(((AbstractDirectMapping)mapping).getAttributeClassificationName()); } else if (getterMethod != null) { - MetadataMethod method = metadataClass.getMethod(getterMethod, new ArrayList(), checkSuperclass); + MetadataMethod method = metadataClass.getMethod(getterMethod, new ArrayList(), checkSuperclass); if (method == null) { return null; } @@ -364,14 +385,14 @@ private MetadataClass getAttributeTypeFromClass(MetadataClass metadataClass, Str * Return the list of mappings that is not specifically found on the given class. These attributes will * be found on MappedSuperclasses. */ - protected List storeAttributeMappings(MetadataClass metadataClass, ClassDetails classDetails, List mappings, boolean weaveValueHolders) { - List unMappedAttributes = new ArrayList(); + protected List storeAttributeMappings(MetadataClass metadataClass, ClassDetails classDetails, List mappings, boolean weaveValueHolders) { + List unMappedAttributes = new ArrayList(); Map attributesMap = new HashMap(); Map settersMap = new HashMap(); Map gettersMap = new HashMap(); - for (Iterator iterator = mappings.iterator(); iterator.hasNext();) { - DatabaseMapping mapping = (DatabaseMapping)iterator.next(); + for (Iterator iterator = mappings.iterator(); iterator.hasNext();) { + DatabaseMapping mapping = iterator.next(); // Can't weave something that isn't really there and not going to be there. if (mapping.isMultitenantPrimaryKeyMapping()) {