mirror of https://github.com/apache/openjpa.git
OPENJPA-2120 Add option for optimizing copy operations for qualifying id classes.
git-svn-id: https://svn.apache.org/repos/asf/openjpa/trunk@1241207 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
e8aaaccf9c
commit
e14af5d7ab
|
@ -1918,5 +1918,37 @@ public interface OpenJPAConfiguration
|
|||
*/
|
||||
public void setPostLoadOnMerge(Boolean postLoadOnMerge);
|
||||
|
||||
/**
|
||||
* Whether to attempt to optimize id class copy operations during the
|
||||
* enhancement process. Optimization is only applicable for simple id classes
|
||||
* that have a constructor with the proper construction parameters and
|
||||
* direct assignments to fields within the id class during construction.
|
||||
* If the optimization cannot occur, the enhancer will fallback to the
|
||||
* noraml behavior.
|
||||
* @since 2.2.0
|
||||
*/
|
||||
public boolean getOptimizeIdCopy();
|
||||
|
||||
/**
|
||||
* Whether to attempt to optimize id class copy operations during the
|
||||
* enhancement process. Optimization is only applicable for simple id classes
|
||||
* that have a constructor with the proper construction parameters and
|
||||
* direct assignments to fields within the id class during construction.
|
||||
* If the optimization cannot occur, the enhancer will fallback to the
|
||||
* normal behavior.
|
||||
* @since 2.2.0
|
||||
*/
|
||||
public void setOptimizeIdCopy(boolean optimizeIds);
|
||||
|
||||
/**
|
||||
* Whether to attempt to optimize id class copy operations during the
|
||||
* enhancement process. Optimization is only applicable for simple id classes
|
||||
* that have a constructor with the proper construction parameters and
|
||||
* direct assignments to fields within the id class during construction.
|
||||
* If the optimization cannot occur, the enhancer will fallback to the
|
||||
* normal behavior.
|
||||
* @since 2.2.0
|
||||
*/
|
||||
public void setOptimizeIdCopy(Boolean optimizeIds);
|
||||
}
|
||||
|
||||
|
|
|
@ -177,6 +177,7 @@ public class OpenJPAConfigurationImpl
|
|||
public ObjectValue instrumentationManager;
|
||||
public PluginListValue instrumentationProviders;
|
||||
public BooleanValue postLoadOnMerge;
|
||||
public BooleanValue optimizeIdCopy;
|
||||
|
||||
// custom values
|
||||
public BrokerFactoryValue brokerFactoryPlugin;
|
||||
|
@ -402,6 +403,10 @@ public class OpenJPAConfigurationImpl
|
|||
postLoadOnMerge.setDefault("false");
|
||||
postLoadOnMerge.set(false);
|
||||
|
||||
optimizeIdCopy = addBoolean("OptimizeIdCopy");
|
||||
optimizeIdCopy.setDefault("false");
|
||||
optimizeIdCopy.set(false);
|
||||
|
||||
autoClear = addInt("AutoClear");
|
||||
aliases =
|
||||
new String[] { "datastore",
|
||||
|
@ -1856,5 +1861,18 @@ public class OpenJPAConfigurationImpl
|
|||
setPostLoadOnMerge(postLoadOnMerge.booleanValue());
|
||||
}
|
||||
|
||||
public boolean getOptimizeIdCopy() {
|
||||
return optimizeIdCopy.get();
|
||||
}
|
||||
|
||||
public void setOptimizeIdCopy(boolean optimizeId) {
|
||||
optimizeIdCopy.set(optimizeId);
|
||||
}
|
||||
|
||||
public void setOptimizeIdCopy(Boolean optimizeId) {
|
||||
if (optimizeId != null) {
|
||||
setOptimizeIdCopy(optimizeId.booleanValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -69,6 +69,7 @@ import org.apache.openjpa.meta.FieldMetaData;
|
|||
import org.apache.openjpa.meta.JavaTypes;
|
||||
import org.apache.openjpa.meta.MetaDataRepository;
|
||||
import org.apache.openjpa.meta.ValueStrategies;
|
||||
import org.apache.openjpa.util.ApplicationIds;
|
||||
import org.apache.openjpa.util.GeneralException;
|
||||
import org.apache.openjpa.util.InternalException;
|
||||
import org.apache.openjpa.util.BigDecimalId;
|
||||
|
@ -102,6 +103,7 @@ import serp.bytecode.LoadInstruction;
|
|||
import serp.bytecode.LookupSwitchInstruction;
|
||||
import serp.bytecode.MethodInstruction;
|
||||
import serp.bytecode.Project;
|
||||
import serp.bytecode.PutFieldInstruction;
|
||||
import serp.bytecode.TableSwitchInstruction;
|
||||
import serp.bytecode.ClassInstruction;
|
||||
import serp.util.Strings;
|
||||
|
@ -212,6 +214,8 @@ public class PCEnhancer {
|
|||
private boolean _isAlreadySubclassed = false;
|
||||
private boolean _bcsConfigured = false;
|
||||
|
||||
private boolean _optimizeIdCopy = false; // whether to attempt optimizing id copy
|
||||
|
||||
/**
|
||||
* Constructor. Supply configuration and type to enhance. This will look
|
||||
* up the metadata for <code>type</code> from <code>conf</code>'s
|
||||
|
@ -280,6 +284,8 @@ public class PCEnhancer {
|
|||
} else
|
||||
_repos = repos;
|
||||
_meta = _repos.getMetaData(type.getType(), loader, false);
|
||||
|
||||
configureOptimizeIdCopy();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2010,11 +2016,52 @@ public class PCEnhancer {
|
|||
// id.<field> = pc.<field>;
|
||||
FieldMetaData[] fmds = getCreateSubclass() ? _meta.getFields()
|
||||
: _meta.getDeclaredFields();
|
||||
Class type;
|
||||
Class<?> type;
|
||||
String name;
|
||||
Field field;
|
||||
Method setter;
|
||||
boolean reflect;
|
||||
// If optimizeIdCopy is enabled and not a field manager method, try to
|
||||
// optimize the copyTo by using a public constructor instead of reflection
|
||||
if (_optimizeIdCopy && !fieldManager) {
|
||||
ArrayList<Integer> pkfields = optimizeIdCopy(oidType, fmds);
|
||||
if (pkfields != null) {
|
||||
// search for a constructor on the IdClass that can be used
|
||||
// to construct the IdClass
|
||||
int parmOrder[] = getIdClassConstructorParmOrder(oidType, pkfields, fmds);
|
||||
if (parmOrder != null) {
|
||||
// found a matching constructor. parm array is constructor parm order
|
||||
code.anew().setType(oidType);
|
||||
code.dup();
|
||||
// build the parm list in order
|
||||
Class<?>[] clsArgs = new Class<?>[parmOrder.length];
|
||||
for (int i = 0; i < clsArgs.length; i++) {
|
||||
int parmIndex = parmOrder[i];
|
||||
clsArgs[i] = fmds[parmIndex].getObjectIdFieldType();
|
||||
loadManagedInstance(code, false);
|
||||
addGetManagedValueCode(code, fmds[parmIndex]);
|
||||
}
|
||||
// invoke the public constructor to create a new local id
|
||||
code.invokespecial().setMethod(oidType, "<init>", void.class, clsArgs);
|
||||
int ret = code.getNextLocalsIndex();
|
||||
code.astore().setLocal(ret);
|
||||
|
||||
// swap out the app id with the new one
|
||||
code.aload().setLocal(1);
|
||||
code.checkcast().setType(ObjectId.class);
|
||||
code.aload().setLocal(ret);
|
||||
code.invokestatic().setMethod(ApplicationIds.class,
|
||||
"setAppId", void.class, new Class[] { ObjectId.class,
|
||||
Object.class });
|
||||
code.vreturn();
|
||||
|
||||
code.calculateMaxStack();
|
||||
code.calculateMaxLocals();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < fmds.length; i++) {
|
||||
if (!fmds[i].isPrimaryKey())
|
||||
continue;
|
||||
|
@ -2428,17 +2475,28 @@ public class PCEnhancer {
|
|||
if (Modifier.isPublic(field.getModifiers()))
|
||||
code.getfield().setField(field);
|
||||
else {
|
||||
// Reflection.getXXX(oid, Reflection.findField(...));
|
||||
code.classconstant().setClass(oidType);
|
||||
code.constant().setValue(name);
|
||||
code.constant().setValue(true);
|
||||
code.invokestatic().setMethod(Reflection.class,
|
||||
"findField", Field.class, new Class[] {
|
||||
Class.class, String.class, boolean.class });
|
||||
code.invokestatic().setMethod
|
||||
(getReflectionGetterMethod(type, Field.class));
|
||||
if (!type.isPrimitive() && type != Object.class)
|
||||
code.checkcast().setType(type);
|
||||
boolean usedFastOid = false;
|
||||
if (_optimizeIdCopy) {
|
||||
// If fastOids, ignore access type and try to use a public getter
|
||||
getter = Reflection.findGetter(oidType, name, false);
|
||||
if (getter != null && Modifier.isPublic(getter.getModifiers())) {
|
||||
usedFastOid = true;
|
||||
code.invokevirtual().setMethod(getter);
|
||||
}
|
||||
}
|
||||
if (!usedFastOid) {
|
||||
// Reflection.getXXX(oid, Reflection.findField(...));
|
||||
code.classconstant().setClass(oidType);
|
||||
code.constant().setValue(name);
|
||||
code.constant().setValue(true);
|
||||
code.invokestatic().setMethod(Reflection.class,
|
||||
"findField", Field.class, new Class[] {
|
||||
Class.class, String.class, boolean.class });
|
||||
code.invokestatic().setMethod
|
||||
(getReflectionGetterMethod(type, Field.class));
|
||||
if (!type.isPrimitive() && type != Object.class)
|
||||
code.checkcast().setType(type);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
getter = Reflection.findGetter(oidType, name, true);
|
||||
|
@ -4823,4 +4881,116 @@ public class PCEnhancer {
|
|||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the optimizedIdCopy value from the config (if available)
|
||||
*/
|
||||
private void configureOptimizeIdCopy() {
|
||||
if (_repos != null && _repos.getConfiguration() != null) {
|
||||
_optimizeIdCopy = _repos.getConfiguration().getOptimizeIdCopy();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Cycles through all primary keys verifying whether they can and should
|
||||
* be used for faster oid copy. The field must be private and must
|
||||
* not have a public setter. If this is the case, the list of pk fields is
|
||||
* returned. If not, returns null.
|
||||
*/
|
||||
private ArrayList<Integer> optimizeIdCopy(Class<?> oidType, FieldMetaData[] fmds) {
|
||||
// collect all object id fields and verify they
|
||||
// a) have a private field
|
||||
// b) do not have a public setter
|
||||
ArrayList<Integer> pkFields = new ArrayList<Integer>();
|
||||
// build list of primary key fields
|
||||
for (int i = 0; i < fmds.length; i++) {
|
||||
if (!fmds[i].isPrimaryKey())
|
||||
continue;
|
||||
// optimizing copy with PC type not (yet) supported
|
||||
if (fmds[i].getDeclaredTypeCode() == JavaTypes.PC) {
|
||||
return null;
|
||||
}
|
||||
String name = fmds[i].getName();
|
||||
Field fld = Reflection.findField(oidType, name, false);
|
||||
if (fld == null || Modifier.isPublic(fld.getModifiers())) {
|
||||
return null;
|
||||
}
|
||||
Method setter = Reflection.findSetter(oidType, name, false);
|
||||
if (setter == null || !Modifier.isPublic(setter.getModifiers())) {
|
||||
pkFields.add(i);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return pkFields.size() > 0 ? pkFields : null;
|
||||
}
|
||||
|
||||
/*
|
||||
* Cycles through all constructors of an IdClass and examines the instructions to find
|
||||
* a matching constructor for the provided pk fields. If a match is found, it returns
|
||||
* the order (relative to the field metadata) of the constructor parameters. If a match
|
||||
* is not found, returns null.
|
||||
*/
|
||||
private int[] getIdClassConstructorParmOrder(Class<?> oidType, ArrayList<Integer> pkfields,
|
||||
FieldMetaData[] fmds) {
|
||||
Project project = new Project();
|
||||
BCClass bc = project.loadClass(oidType);
|
||||
BCMethod[] methods = bc.getDeclaredMethods("<init>");
|
||||
if (methods == null || methods.length == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
int parmOrder[] = new int[pkfields.size()];
|
||||
for (BCMethod method : methods) {
|
||||
// constructor must be public
|
||||
if (!method.isPublic()) {
|
||||
continue;
|
||||
}
|
||||
Class<?>[] parmTypes = method.getParamTypes();
|
||||
// make sure the constructors have the same # of parms as
|
||||
// the number of pk fields
|
||||
if (parmTypes.length != pkfields.size()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int parmOrderIndex = 0;
|
||||
Code code = method.getCode(false);
|
||||
Instruction[] ins = code.getInstructions();
|
||||
for (int i = 0; i < ins.length; i++) {
|
||||
if (ins[i] instanceof PutFieldInstruction) {
|
||||
PutFieldInstruction pfi = (PutFieldInstruction)ins[i];
|
||||
for (int j = 0; j < pkfields.size(); j++) {
|
||||
int fieldNum = pkfields.get(j);
|
||||
// Compare the field being set with the current pk field
|
||||
String parmName = fmds[fieldNum].getName();
|
||||
Class<?> parmType = fmds[fieldNum].getType();
|
||||
if (parmName.equals(pfi.getFieldName())) {
|
||||
// backup and examine the load instruction parm
|
||||
if (i > 0 && ins[i-1] instanceof LoadInstruction) {
|
||||
LoadInstruction li = (LoadInstruction)ins[i-1];
|
||||
// Get the local index from the instruction. This will be the index
|
||||
// of the constructor parameter. must be less than or equal to the
|
||||
// max parm index to prevent from picking up locals that could have
|
||||
// been produced within the constructor. Also make sure the parm type
|
||||
// matches the fmd type
|
||||
int parm = li.getLocal();
|
||||
if (parm <= pkfields.size() && parmTypes[parm-1].equals(parmType)) {
|
||||
parmOrder[parmOrderIndex] = fieldNum;
|
||||
parmOrderIndex++;
|
||||
}
|
||||
} else {
|
||||
// Some other instruction found. can't make a determination of which local/parm
|
||||
// is being used on the putfield.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (parmOrderIndex == pkfields.size()) {
|
||||
return parmOrder;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -575,6 +575,14 @@ public class ApplicationIds {
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the underlying id of an ObjectId. Should only
|
||||
* be used with simple (idclass) types.
|
||||
*/
|
||||
public static void setAppId(ObjectId id, Object newId) {
|
||||
id.setId(newId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper class used to transfer pk values to/from application oids.
|
||||
*/
|
||||
|
|
|
@ -31,12 +31,12 @@
|
|||
<istrue value="${maven.test.skip}" />
|
||||
</condition>
|
||||
|
||||
<condition property="skip.enhance">
|
||||
<or>
|
||||
<condition property="skip.enhance">
|
||||
<or>
|
||||
<equals arg1="${test}" arg2="false" />
|
||||
<equals arg1="${build.enhance}" arg2="false" />
|
||||
<istrue value="${maven.test.skip}" />
|
||||
<istrue value="${skipTests}" />
|
||||
<equals arg1="${build.enhance}" arg2="false" />
|
||||
<istrue value="${maven.test.skip}" />
|
||||
<istrue value="${skipTests}" />
|
||||
</or>
|
||||
</condition>
|
||||
|
||||
|
@ -83,7 +83,8 @@
|
|||
<exclude name="org/apache/openjpa/enhance/EnhancedSubClass.class"/>
|
||||
<exclude name="**/AbstractUnenhanced*.class" />
|
||||
<exclude name="**/unenhanced/*.class" />
|
||||
<exclude name="**/persistence/property/AccessModsEntity.class"/>
|
||||
<exclude name="**/persistence/property/AccessModsEntity.class"/>
|
||||
<exclude name="org/apache/openjpa/enhance/ids/*.class"/>
|
||||
</fileset>
|
||||
<openjpac>
|
||||
<classpath refid="cp" />
|
||||
|
@ -99,17 +100,17 @@
|
|||
<include name="**/detach/serializable/*.class" />
|
||||
<!-- include files from orm.xml -->
|
||||
<include name="**/xml/*.class" />
|
||||
<exclude name="**/persistence/delimited/identifiers/xml/*.class"/>
|
||||
<exclude name="**/persistence/delimited/identifiers/xml/*.class"/>
|
||||
<exclude name="**/Test*.class" />
|
||||
</fileset>
|
||||
<config log="${openjpa.Log}" />
|
||||
</openjpac>
|
||||
<!-- Enhance with private persistent properties compatibility option -->
|
||||
<!-- Enhance with private persistent properties compatibility option -->
|
||||
<openjpac>
|
||||
<config propertiesFile="${project.build.testOutputDirectory}/META-INF/nopriv_persistence.xml" />
|
||||
<classpath refid="cp" />
|
||||
<fileset dir="${project.build.testOutputDirectory}">
|
||||
<include name="**/persistence/property/AccessModsEntity.class"/>
|
||||
<include name="**/persistence/property/AccessModsEntity.class"/>
|
||||
</fileset>
|
||||
<config log="${openjpa.Log}" />
|
||||
</openjpac>
|
||||
|
@ -132,15 +133,24 @@
|
|||
</fileset>
|
||||
<config log="${openjpa.Log}" />
|
||||
</openjpac>
|
||||
<!-- Enhance delimited identifiers XML-based entities separately -->
|
||||
<!-- Enhance delimited identifiers XML-based entities separately -->
|
||||
<openjpac>
|
||||
<config propertiesFile="${project.build.testOutputDirectory}/META-INF/delim_persistence.xml" />
|
||||
<classpath refid="cp" />
|
||||
<fileset dir="${project.build.testOutputDirectory}">
|
||||
<include name="**/persistence/delimited/identifiers/xml/*.class"/>
|
||||
<exclude name="**/persistence/delimited/identifiers/xml/Test*.class"/>
|
||||
<include name="**/persistence/delimited/identifiers/xml/*.class"/>
|
||||
<exclude name="**/persistence/delimited/identifiers/xml/Test*.class"/>
|
||||
</fileset>
|
||||
<config log="${openjpa.Log}"/>
|
||||
</openjpac>
|
||||
<!-- Enhance with optimized id copy option -->
|
||||
<openjpac>
|
||||
<config propertiesFile="${project.build.testOutputDirectory}/META-INF/optidcpy_persistence.xml" />
|
||||
<classpath refid="cp" />
|
||||
<fileset dir="${project.build.testOutputDirectory}">
|
||||
<include name="org/apache/openjpa/enhance/ids/*.class"/>
|
||||
</fileset>
|
||||
<config log="${openjpa.Log}" />
|
||||
</openjpac>
|
||||
</target>
|
||||
</project>
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* 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.enhance.ids;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.IdClass;
|
||||
import javax.persistence.Table;
|
||||
|
||||
@Entity
|
||||
@Table(name="ID_DEVTBL")
|
||||
@IdClass(DeviceId.class)
|
||||
public class Device {
|
||||
|
||||
@Id
|
||||
@Column(name="DEV_ID")
|
||||
private int id;
|
||||
|
||||
@Id
|
||||
@Column(name="DEV_TYPE")
|
||||
private int type;
|
||||
|
||||
@Column(name="DEV_DESC")
|
||||
private String description;
|
||||
|
||||
public Device() {
|
||||
|
||||
}
|
||||
|
||||
public void setId(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setType(int type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public int getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
}
|
|
@ -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.enhance.ids;
|
||||
|
||||
public class DeviceId {
|
||||
|
||||
public static boolean[] usedConstructor = new boolean[3];
|
||||
|
||||
private int id;
|
||||
|
||||
private int type;
|
||||
|
||||
public DeviceId() {
|
||||
usedConstructor[0] = true;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private DeviceId(int i, int t) {
|
||||
usedConstructor[1] = true;
|
||||
id = i;
|
||||
type = t;
|
||||
}
|
||||
|
||||
public DeviceId(int i) {
|
||||
usedConstructor[2] = true;
|
||||
id = i;
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public int getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj instanceof DeviceId) {
|
||||
DeviceId did = (DeviceId)obj;
|
||||
return did.getId() == getId() &&
|
||||
did.getType() == getType();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return getId() + getType();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* 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.enhance.ids;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.IdClass;
|
||||
import javax.persistence.Table;
|
||||
|
||||
@Table(name="ID_HWTBL")
|
||||
@IdClass(HardwareId.class)
|
||||
@Entity
|
||||
public class Hardware {
|
||||
|
||||
@Id
|
||||
private String serial;
|
||||
|
||||
@Id
|
||||
private String model;
|
||||
|
||||
private String description;
|
||||
|
||||
public Hardware() {
|
||||
}
|
||||
|
||||
public void setSerial(String serial) {
|
||||
this.serial = serial;
|
||||
}
|
||||
|
||||
public String getSerial() {
|
||||
return serial;
|
||||
}
|
||||
|
||||
public void setModel(String model) {
|
||||
this.model = model;
|
||||
}
|
||||
|
||||
public String getModel() {
|
||||
return model;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
}
|
|
@ -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.enhance.ids;
|
||||
|
||||
public class HardwareId {
|
||||
|
||||
public static boolean[] usedConstructor = new boolean[2];
|
||||
|
||||
private String serial;
|
||||
|
||||
private String model;
|
||||
|
||||
public HardwareId() {
|
||||
}
|
||||
|
||||
// Parms out of order
|
||||
public HardwareId(String model, String serial) {
|
||||
usedConstructor[0] = true;
|
||||
this.serial = serial;
|
||||
this.model = model;
|
||||
}
|
||||
|
||||
public HardwareId(String model,int serial) {
|
||||
usedConstructor[1] = true;
|
||||
this.model = model;
|
||||
this.serial = Integer.toString(serial);
|
||||
}
|
||||
|
||||
public String getSerial() {
|
||||
return serial;
|
||||
}
|
||||
|
||||
public String getModel() {
|
||||
return model;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj instanceof HardwareId) {
|
||||
HardwareId hid = (HardwareId)obj;
|
||||
return hid.getModel().equals(getModel()) &&
|
||||
hid.getSerial().equals(getSerial());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return getSerial().hashCode() + getModel().hashCode();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* 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.enhance.ids;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.IdClass;
|
||||
import javax.persistence.Table;
|
||||
|
||||
@Entity
|
||||
@Table(name="ID_SWTBL")
|
||||
@IdClass(SoftwareId.class)
|
||||
public class Software {
|
||||
|
||||
@Id
|
||||
private Integer idInteger;
|
||||
|
||||
@Id
|
||||
private int idInt;
|
||||
|
||||
@Id
|
||||
private String idString;
|
||||
|
||||
public Software() {
|
||||
|
||||
}
|
||||
|
||||
public void setIdInteger(Integer idInteger) {
|
||||
this.idInteger = idInteger;
|
||||
}
|
||||
|
||||
public Integer getIdInteger() {
|
||||
return idInteger;
|
||||
}
|
||||
|
||||
public void setIdInt(int idInt) {
|
||||
this.idInt = idInt;
|
||||
}
|
||||
|
||||
public int getIdInt() {
|
||||
return idInt;
|
||||
}
|
||||
|
||||
public void setIdString(String idString) {
|
||||
this.idString = idString;
|
||||
}
|
||||
|
||||
public String getIdString() {
|
||||
return idString;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* 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.enhance.ids;
|
||||
|
||||
public class SoftwareId {
|
||||
|
||||
public static boolean[] usedConstructor = new boolean[3];
|
||||
|
||||
private Integer idInteger;
|
||||
|
||||
private int idInt;
|
||||
|
||||
private String idString;
|
||||
|
||||
public SoftwareId() {
|
||||
|
||||
}
|
||||
|
||||
public SoftwareId(int idint) {
|
||||
usedConstructor[0] = true;
|
||||
idInt = idint;
|
||||
}
|
||||
|
||||
public SoftwareId(Integer idinteger, int idint) {
|
||||
usedConstructor[1] = true;
|
||||
idInteger = idinteger;
|
||||
idInt = idint;
|
||||
}
|
||||
|
||||
public SoftwareId(Integer idinteger, int idint, String idstring) {
|
||||
usedConstructor[2] = true;
|
||||
idInteger = idinteger;
|
||||
idInt = idint;
|
||||
idString =idstring;
|
||||
}
|
||||
public Integer getIdInteger() {
|
||||
return idInteger;
|
||||
}
|
||||
|
||||
public int getIdInt() {
|
||||
return idInt;
|
||||
}
|
||||
|
||||
public String getIdString() {
|
||||
return idString;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj instanceof SoftwareId) {
|
||||
SoftwareId swid = (SoftwareId)obj;
|
||||
return swid.getIdInt() == getIdInt() &&
|
||||
swid.getIdInteger().equals(getIdInteger()) &&
|
||||
swid.getIdString().equals(getIdString());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return getIdInt() + getIdInteger().hashCode() + getIdString().hashCode();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,122 @@
|
|||
/*
|
||||
* 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.enhance.ids;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.TypedQuery;
|
||||
|
||||
import org.apache.openjpa.persistence.test.SingleEMFTestCase;
|
||||
|
||||
/**
|
||||
* Verifies the use of the openjpa.OptimizeIdCopy configuration parameter. This parameter
|
||||
* changes the behavior of the enhancer and thus, must be set before enhancement occurs. There
|
||||
* is special enhancement task in main/ant/enhancer.xml to ensure this value is set
|
||||
* during the enhancement process for the entities used by this test.
|
||||
*/
|
||||
public class TestOptimizeIdCopy extends SingleEMFTestCase {
|
||||
|
||||
@Override
|
||||
public void setUp() {
|
||||
setUp(Device.class,Hardware.class,Software.class, CLEAR_TABLES);
|
||||
}
|
||||
|
||||
/*
|
||||
* Verifies that constructor-based Id optimization occurs during Id copy. Asserts
|
||||
* only the proper/expected public constructor is called during the id copy operation.
|
||||
*/
|
||||
public void testIdOptimization() {
|
||||
EntityManager em = emf.createEntityManager();
|
||||
|
||||
// Add a software entity
|
||||
Software sw = new Software();
|
||||
int id = new Random().nextInt();
|
||||
sw.setIdInt(id);
|
||||
sw.setIdInteger(10);
|
||||
sw.setIdString("StringIdVal");
|
||||
|
||||
em.getTransaction().begin();
|
||||
em.persist(sw);
|
||||
em.getTransaction().commit();
|
||||
em.clear();
|
||||
|
||||
TypedQuery<Software> swq = em.createQuery("select sw from Software sw", Software.class);
|
||||
List<Software> swl = swq.getResultList();
|
||||
assertTrue("Software result list > 0", swl.size() > 0);
|
||||
// Id copy optimization should have used the 3rd constructor
|
||||
assertFalse("First constructor was not used", SoftwareId.usedConstructor[0]);
|
||||
assertFalse("Second constructor was not used", SoftwareId.usedConstructor[1]);
|
||||
assertTrue("Third (correct) constructor was used", SoftwareId.usedConstructor[2]);
|
||||
em.close();
|
||||
}
|
||||
|
||||
/*
|
||||
* Verifies that constructor based optimization functions even if parms
|
||||
* are different than field order
|
||||
*/
|
||||
public void testIdOptimizationConstructorOutOfOrder() {
|
||||
EntityManager em = emf.createEntityManager();
|
||||
|
||||
Hardware hw = new Hardware();
|
||||
String id = "Model" + (new Random().nextInt());
|
||||
hw.setModel("Model" + id);
|
||||
hw.setSerial("123XYZ");
|
||||
|
||||
em.getTransaction().begin();
|
||||
em.persist(hw);
|
||||
em.getTransaction().commit();
|
||||
em.clear();
|
||||
|
||||
TypedQuery<Hardware> hwq = em.createQuery("select hw from Hardware hw", Hardware.class);
|
||||
List<Hardware> hwl = hwq.getResultList();
|
||||
assertTrue("Hardware result list > 0", hwl.size() > 0);
|
||||
// Id copy optimization should have used the first constructor
|
||||
assertTrue("First (correct) constructor was used", HardwareId.usedConstructor[0]);
|
||||
assertFalse("Second constructor was not used", HardwareId.usedConstructor[1]);
|
||||
em.close();
|
||||
}
|
||||
|
||||
/*
|
||||
* Verifies that classes without a proper constructor do not get optimized
|
||||
*/
|
||||
public void testNoOptimization() {
|
||||
EntityManager em = emf.createEntityManager();
|
||||
|
||||
int id = new Random().nextInt();
|
||||
Device d = new Device();
|
||||
d.setId(id);
|
||||
d.setType(10);
|
||||
|
||||
em.getTransaction().begin();
|
||||
em.persist(d);
|
||||
em.getTransaction().commit();
|
||||
em.clear();
|
||||
|
||||
TypedQuery<Device> dq = em.createQuery("select d from Device d", Device.class);
|
||||
List<Device> dl = dq.getResultList();
|
||||
assertTrue("Device result list > 0", dl.size() > 0);
|
||||
// Only the first, default constructor should have been called
|
||||
assertTrue("First (default) constructor was used", DeviceId.usedConstructor[0]);
|
||||
assertFalse("Second constructor was not used", DeviceId.usedConstructor[1]);
|
||||
assertFalse("Third constructor was not used", DeviceId.usedConstructor[2]);
|
||||
em.close();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
<persistence
|
||||
xmlns="http://java.sun.com/xml/ns/persistence"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
|
||||
http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
|
||||
version="2.0" >
|
||||
|
||||
<persistence-unit name="OptimizeIdCopy_PU">
|
||||
<description>
|
||||
This PU
|
||||
</description>
|
||||
<class>org.apache.openjpa.enhance.ids.Device</class>
|
||||
<class>org.apache.openjpa.enhance.ids.Hardware</class>
|
||||
<class>org.apache.openjpa.enhance.ids.Software</class>
|
||||
<properties>
|
||||
<property name="openjpa.OptimizeIdCopy" value="true"/>
|
||||
</properties>
|
||||
</persistence-unit>
|
||||
</persistence>
|
Loading…
Reference in New Issue