Skip to content

Commit

Permalink
Bug 412391: Add support for hidden mappedsuperclass attributes
Browse files Browse the repository at this point in the history
Signed-off-by: Will Dazey <[email protected]>
  • Loading branch information
dazey3 committed Sep 27, 2021
1 parent 5da4eef commit 036658a
Show file tree
Hide file tree
Showing 4 changed files with 198 additions and 22 deletions.
Original file line number Diff line number Diff line change
@@ -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();
}
}
}
}
Original file line number Diff line number Diff line change
@@ -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;
}
}
Original file line number Diff line number Diff line change
@@ -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;
}
}
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -111,7 +112,7 @@ public TransformerFactory(Session session, Collection<MetadataClass> 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<String, ClassDetails> classDetailsMap, List<DatabaseMapping> unMappedAttributes, boolean weaveChangeTracking){
MetadataClass superClz = clz.getSuperclass();
if (superClz == null || superClz.isObject()){
return;
Expand All @@ -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<DatabaseMapping> hiddenMappings = new ArrayList<DatabaseMapping>();
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<DatabaseMapping> stillUnMappedMappings = null;
ClassDetails superClassDetails = createClassDetails(superClz, weaveValueHolders, weaveChangeTracking, weaveFetchGroups, weaveInternal, weaveRest);
superClassDetails.setIsMappedSuperClass(true);

Expand Down Expand Up @@ -193,7 +214,7 @@ public void buildClassDetailsAndModifyProject() {

classDetails.getVirtualAccessMethods().addAll(descriptor.getVirtualAttributeMethods());

List unMappedAttributes = storeAttributeMappings(metaClass, classDetails, descriptor.getMappings(), weaveValueHoldersForClass);
List<DatabaseMapping> unMappedAttributes = storeAttributeMappings(metaClass, classDetails, descriptor.getMappings(), weaveValueHoldersForClass);
classDetailsMap.put(classDetails.getClassName() ,classDetails);

classDetails.setShouldWeaveConstructorOptimization((classDetails.getDescribedClass().getFields().size() - (descriptor.getMappings().size() - unMappedAttributes.size()))<=0);
Expand All @@ -204,8 +225,8 @@ public void buildClassDetailsAndModifyProject() {
}

// hookup superClassDetails
for (Iterator i = classDetailsMap.values().iterator(); i.hasNext();) {
ClassDetails classDetails = (ClassDetails)i.next();
for (Iterator<ClassDetails> 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());
Expand All @@ -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<ClassDetails> i = classDetailsMap.values().iterator(); i.hasNext();) {
ClassDetails classDetails = i.next();
classDetails.setShouldWeaveChangeTracking(classDetails.canWeaveChangeTracking());
}
}
Expand Down Expand Up @@ -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;
}
Expand All @@ -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<DatabaseMapping> 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<DatabaseMapping> iterator = mappings.iterator(); iterator.hasNext();) {
DatabaseMapping mapping = iterator.next();
String attributeName = mapping.getAttributeName();
if (mapping.isForeignReferenceMapping()) {
ForeignReferenceMapping foreignReferenceMapping = (ForeignReferenceMapping)mapping;
Expand Down Expand Up @@ -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<String>(), false);
classDetails.setImplementsCloneMethod(method != null);
return classDetails;
}
Expand All @@ -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<ClassDescriptor> iterator = project.getOrderedDescriptors().iterator();
while (iterator.hasNext()){
ClassDescriptor descriptor = (ClassDescriptor)iterator.next();
ClassDescriptor descriptor = iterator.next();
if (descriptor.getJavaClassName().equals(className)){
return descriptor;
}
Expand Down Expand Up @@ -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<String>(), checkSuperclass);
if (method == null) {
return null;
}
Expand All @@ -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<DatabaseMapping> storeAttributeMappings(MetadataClass metadataClass, ClassDetails classDetails, List<DatabaseMapping> mappings, boolean weaveValueHolders) {
List<DatabaseMapping> unMappedAttributes = new ArrayList<DatabaseMapping>();
Map<String, AttributeDetails> attributesMap = new HashMap<String, AttributeDetails>();
Map<String, AttributeDetails> settersMap = new HashMap<String, AttributeDetails>();
Map<String, AttributeDetails> gettersMap = new HashMap<String, AttributeDetails>();

for (Iterator iterator = mappings.iterator(); iterator.hasNext();) {
DatabaseMapping mapping = (DatabaseMapping)iterator.next();
for (Iterator<DatabaseMapping> 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()) {
Expand Down

0 comments on commit 036658a

Please sign in to comment.