OPENJPA-2911 move ApplicationIdTool from Serp to ASM

This commit is contained in:
Mark Struberg 2023-05-16 08:17:57 +02:00
parent f19ba018e2
commit 39c838a56f
7 changed files with 203 additions and 73 deletions

View File

@ -57,12 +57,12 @@ import org.apache.openjpa.meta.JavaTypes;
import org.apache.openjpa.meta.MetaDataFactory; import org.apache.openjpa.meta.MetaDataFactory;
import org.apache.openjpa.meta.MetaDataModes; import org.apache.openjpa.meta.MetaDataModes;
import org.apache.openjpa.meta.MetaDataRepository; import org.apache.openjpa.meta.MetaDataRepository;
import org.apache.openjpa.util.GeneratedClasses;
import org.apache.openjpa.util.InvalidStateException; import org.apache.openjpa.util.InvalidStateException;
import org.apache.openjpa.util.UserException; import org.apache.openjpa.util.UserException;
import org.apache.xbean.asm9.ClassWriter;
import serp.bytecode.BCClass; import org.apache.xbean.asm9.Opcodes;
import serp.bytecode.BCClassLoader; import org.apache.xbean.asm9.Type;
import serp.bytecode.Project;
/** /**
* Generates a class appropriate for use as an application identity class. * Generates a class appropriate for use as an application identity class.
@ -116,8 +116,7 @@ public class ApplicationIdTool {
* Constructs a new tool instance capable of generating an * Constructs a new tool instance capable of generating an
* object id class for <code>meta</code>. * object id class for <code>meta</code>.
*/ */
public ApplicationIdTool(OpenJPAConfiguration conf, Class type, public ApplicationIdTool(OpenJPAConfiguration conf, Class type, ClassMetaData meta) {
ClassMetaData meta) {
_log = conf.getLog(OpenJPAConfiguration.LOG_ENHANCE); _log = conf.getLog(OpenJPAConfiguration.LOG_ENHANCE);
_type = type; _type = type;
@ -1375,14 +1374,12 @@ public class ApplicationIdTool {
ApplicationIdTool tool; ApplicationIdTool tool;
Class cls; Class cls;
ClassMetaData meta; ClassMetaData meta;
BCClassLoader bc = AccessController
.doPrivileged(J2DoPrivHelper.newBCClassLoaderAction(new Project()));
for (Object aClass : classes) { for (Object aClass : classes) {
cls = (Class) aClass; cls = (Class) aClass;
log.info(_loc.get("appid-running", cls)); log.info(_loc.get("appid-running", cls));
meta = repos.getMetaData(cls, null, false); meta = repos.getMetaData(cls, null, false);
setObjectIdType(meta, flags, bc); setObjectIdType(meta, flags);
tool = new ApplicationIdTool(conf, cls, meta); tool = new ApplicationIdTool(conf, cls, meta);
tool.setDirectory(flags.directory); tool.setDirectory(flags.directory);
@ -1396,15 +1393,13 @@ public class ApplicationIdTool {
else else
log.info(_loc.get("appid-norun")); log.info(_loc.get("appid-norun"));
} }
bc.getProject().clear();
return true; return true;
} }
/** /**
* Set the object id type of the given metadata. * Set the object id type of the given metadata.
*/ */
private static void setObjectIdType(ClassMetaData meta, Flags flags, private static void setObjectIdType(ClassMetaData meta, Flags flags)
BCClassLoader bc)
throws ClassNotFoundException { throws ClassNotFoundException {
if (meta == null || (meta.getObjectIdType() != null if (meta == null || (meta.getObjectIdType() != null
&& (!meta.isOpenJPAIdentity() || flags.name == null)) && (!meta.isOpenJPAIdentity() || flags.name == null))
@ -1413,18 +1408,19 @@ public class ApplicationIdTool {
Class desc = meta.getDescribedType(); Class desc = meta.getDescribedType();
Class cls = null; Class cls = null;
if (flags.name != null) if (flags.name != null) {
cls = loadClass(desc, flags.name, bc); cls = loadClass(desc, flags.name);
else if (flags.suffix != null) }
cls = loadClass(desc, desc.getName() + flags.suffix, bc); else if (flags.suffix != null) {
cls = loadClass(desc, desc.getName() + flags.suffix);
}
meta.setObjectIdType(cls, false); meta.setObjectIdType(cls, false);
} }
/** /**
* Load the given class name even if it does not exist. * Load the given class name even if it does not exist.
*/ */
private static Class loadClass(Class context, String name, private static Class loadClass(Class context, String name)
BCClassLoader bc)
throws ClassNotFoundException { throws ClassNotFoundException {
if (name.indexOf('.') == -1 && context.getName().indexOf('.') != -1) if (name.indexOf('.') == -1 && context.getName().indexOf('.') != -1)
name = ClassUtil.getPackageName(context) + "." + name; name = ClassUtil.getPackageName(context) + "." + name;
@ -1441,9 +1437,16 @@ public class ApplicationIdTool {
} }
// create class // create class
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
cw.visit(Opcodes.V11, Opcodes.ACC_PUBLIC + Opcodes.ACC_SUPER, name.replace(".", "/"),
null, Type.getInternalName(Object.class), null);
return GeneratedClasses.loadAsmClass(name, cw.toByteArray(), context, context.getClassLoader());
/*X TODO DELETE
BCClass oid = bc.getProject().loadClass(name, null); BCClass oid = bc.getProject().loadClass(name, null);
oid.addDefaultConstructor(); oid.addDefaultConstructor();
return Class.forName(name, false, bc); return Class.forName(name, false, bc);
*/
} }
/** /**

View File

@ -87,6 +87,7 @@
<exclude name="**/unenhanced/*.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"/> <exclude name="org/apache/openjpa/enhance/ids/*.class"/>
<exclude name="org/apache/openjpa/idtool/RecordsPerYear.class"/>
</fileset> </fileset>
<openjpac> <openjpac>
<classpath refid="cp" /> <classpath refid="cp" />

View File

@ -149,7 +149,8 @@ public class TestEnhancementWithMultiplePUs
// not attempt to enhance. // not attempt to enhance.
opts.setProperty("MetaDataRepository", opts.setProperty("MetaDataRepository",
"org.apache.openjpa.enhance.RestrictedMetaDataRepository(excludedTypes=" + "org.apache.openjpa.enhance.RestrictedMetaDataRepository(excludedTypes=" +
"org.apache.openjpa.persistence.jdbc.annotations.UnenhancedMixedAccess)"); "\"org.apache.openjpa.persistence.jdbc.annotations.UnenhancedMixedAccess," +
"org.apache.openjpa.idtool.RecordsPerYear\")");
opts.put(PCEnhancer.class.getName() + "#bytecodeWriter", writer); opts.put(PCEnhancer.class.getName() + "#bytecodeWriter", writer);
PCEnhancer.run(null, opts); PCEnhancer.run(null, opts);

View File

@ -0,0 +1,59 @@
/*
* 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.idtool;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
/**
* Entity for testing the {@link org.apache.openjpa.enhance.ApplicationIdTool}.
*/
@Entity
public class RecordsPerYear {
@Id
private String user;
@Id
private int year;
private long counter;
public String getUser() {
return user;
}
public void setUser(String user) {
this.user = user;
}
public int getYear() {
return year;
}
public void setYear(int year) {
this.year = year;
}
public long getCounter() {
return counter;
}
public void setCounter(long counter) {
this.counter = counter;
}
}

View File

@ -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.idtool;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import org.apache.openjpa.enhance.ApplicationIdTool;
import org.apache.openjpa.persistence.jdbc.common.apps.AutoIncrementPC3;
import org.junit.Test;
import static org.junit.Assert.assertTrue;
/**
* Test for the ApplicationIdTool from openjpa-kernel.
* We cannot test it over in the openjpa-kernel package as
* we'd not be able to also test JPA features.
*/
public class TestApplicationIdTool {
@Test
public void testApplicationIdTool_wIdClassAnnotation() throws Exception{
String entityJavaFile = "./src/test/java/" + AutoIncrementPC3.class.getName().replace(".", "/") + ".java";
final String outputDir = "./target/idtooltest/";
ApplicationIdTool.main(new String[]{"-s","Id", entityJavaFile, "-d", outputDir});
String idJavaFile = outputDir + AutoIncrementPC3.class.getName().replace(".", "/") + "Id.java";
assertTrue(new File(idJavaFile).exists());
}
@Test
public void testApplicationIdTool_freshClass() throws Exception{
String entityJavaFile = "./src/test/java/" + RecordsPerYear.class.getName().replace(".", "/") + ".java";
final String outputDir = "./target/idtooltest/";
ApplicationIdTool.main(new String[]{"-s","Id", entityJavaFile, "-d", outputDir});
String idJavaFile = outputDir + RecordsPerYear.class.getName().replace(".", "/") + "Id.java";
final File generatedIdFile = new File(idJavaFile);
assertTrue(generatedIdFile.exists());
assertContains(generatedIdFile, "public class RecordsPerYearId");
assertContains(generatedIdFile, "public RecordsPerYearId(String str)");
}
private void assertContains(File file, String find) throws IOException {
final byte[] bytes = Files.readAllBytes(file.toPath());
assertTrue(new String(bytes).contains(find));
}
}

View File

@ -43,6 +43,7 @@ public class AutoIncrementPC3
{ {
@Id @Id
private long id = 0; private long id = 0;
private Set setField = new HashSet (); private Set setField = new HashSet ();
@Column(name="strngfld", length=50) @Column(name="strngfld", length=50)