diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/ant/ApplicationIdToolTask.java b/openjpa-kernel/src/main/java/org/apache/openjpa/ant/ApplicationIdToolTask.java index df19c3566..634f0d852 100755 --- a/openjpa-kernel/src/main/java/org/apache/openjpa/ant/ApplicationIdToolTask.java +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/ant/ApplicationIdToolTask.java @@ -110,5 +110,5 @@ public class ApplicationIdToolTask : Files.getFile(dirName, getClassLoader()); ApplicationIdTool.run((OpenJPAConfiguration) getConfiguration(), files, flags, getClassLoader ()); - } + } } diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/ApplicationIdTool.java b/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/ApplicationIdTool.java index 922b558bb..680991c04 100644 --- a/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/ApplicationIdTool.java +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/ApplicationIdTool.java @@ -57,12 +57,12 @@ import org.apache.openjpa.meta.JavaTypes; import org.apache.openjpa.meta.MetaDataFactory; import org.apache.openjpa.meta.MetaDataModes; import org.apache.openjpa.meta.MetaDataRepository; +import org.apache.openjpa.util.GeneratedClasses; import org.apache.openjpa.util.InvalidStateException; import org.apache.openjpa.util.UserException; - -import serp.bytecode.BCClass; -import serp.bytecode.BCClassLoader; -import serp.bytecode.Project; +import org.apache.xbean.asm9.ClassWriter; +import org.apache.xbean.asm9.Opcodes; +import org.apache.xbean.asm9.Type; /** * 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 * object id class for meta. */ - public ApplicationIdTool(OpenJPAConfiguration conf, Class type, - ClassMetaData meta) { + public ApplicationIdTool(OpenJPAConfiguration conf, Class type, ClassMetaData meta) { _log = conf.getLog(OpenJPAConfiguration.LOG_ENHANCE); _type = type; @@ -828,8 +827,8 @@ public class ApplicationIdTool { append(name).closeParen().closeParen(); } else if (type == char[].class) { // ((name == null && other.name == null) - // || (name != null && String.valueOf (name). - // equals (String.valueOf (other.name)))) + // || (name != null && String.valueOf (name). + // equals (String.valueOf (other.name)))) code.append("(").openParen(false).append(name). append(" == null && other.").append(name). append(" == null").closeParen().endl(); @@ -843,7 +842,7 @@ public class ApplicationIdTool { closeParen().append(")"); } else { // ((name == null && other.name == null) - // || (name != null && name.equals (other.name))) + // || (name != null && name.equals (other.name))) code.append("(").openParen(false).append(name). append(" == null && other.").append(name). append(" == null").closeParen().endl(); @@ -1375,14 +1374,12 @@ public class ApplicationIdTool { ApplicationIdTool tool; Class cls; ClassMetaData meta; - BCClassLoader bc = AccessController - .doPrivileged(J2DoPrivHelper.newBCClassLoaderAction(new Project())); for (Object aClass : classes) { cls = (Class) aClass; log.info(_loc.get("appid-running", cls)); meta = repos.getMetaData(cls, null, false); - setObjectIdType(meta, flags, bc); + setObjectIdType(meta, flags); tool = new ApplicationIdTool(conf, cls, meta); tool.setDirectory(flags.directory); @@ -1396,15 +1393,13 @@ public class ApplicationIdTool { else log.info(_loc.get("appid-norun")); } - bc.getProject().clear(); return true; } /** * Set the object id type of the given metadata. */ - private static void setObjectIdType(ClassMetaData meta, Flags flags, - BCClassLoader bc) + private static void setObjectIdType(ClassMetaData meta, Flags flags) throws ClassNotFoundException { if (meta == null || (meta.getObjectIdType() != null && (!meta.isOpenJPAIdentity() || flags.name == null)) @@ -1413,18 +1408,19 @@ public class ApplicationIdTool { Class desc = meta.getDescribedType(); Class cls = null; - if (flags.name != null) - cls = loadClass(desc, flags.name, bc); - else if (flags.suffix != null) - cls = loadClass(desc, desc.getName() + flags.suffix, bc); + if (flags.name != null) { + cls = loadClass(desc, flags.name); + } + else if (flags.suffix != null) { + cls = loadClass(desc, desc.getName() + flags.suffix); + } meta.setObjectIdType(cls, false); } /** * Load the given class name even if it does not exist. */ - private static Class loadClass(Class context, String name, - BCClassLoader bc) + private static Class loadClass(Class context, String name) throws ClassNotFoundException { if (name.indexOf('.') == -1 && context.getName().indexOf('.') != -1) name = ClassUtil.getPackageName(context) + "." + name; @@ -1441,9 +1437,16 @@ public class ApplicationIdTool { } // 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); oid.addDefaultConstructor(); return Class.forName(name, false, bc); +*/ } /** @@ -1479,11 +1482,11 @@ public class ApplicationIdTool { * object id classes. */ public interface ObjectIdLoader - { - /** + { + /** * Turn on the loading of all identity classes, even if they don't * exist. - */ - void setLoadObjectIds (); - } + */ + void setLoadObjectIds (); + } } diff --git a/openjpa-persistence-jdbc/src/main/ant/enhancer.xml b/openjpa-persistence-jdbc/src/main/ant/enhancer.xml index 6168491c3..8fed7664c 100644 --- a/openjpa-persistence-jdbc/src/main/ant/enhancer.xml +++ b/openjpa-persistence-jdbc/src/main/ant/enhancer.xml @@ -87,6 +87,7 @@ + diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/enhance/TestEnhancementWithMultiplePUs.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/enhance/TestEnhancementWithMultiplePUs.java index adb9fdb65..a6c63ac33 100644 --- a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/enhance/TestEnhancementWithMultiplePUs.java +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/enhance/TestEnhancementWithMultiplePUs.java @@ -149,7 +149,8 @@ public class TestEnhancementWithMultiplePUs // not attempt to enhance. opts.setProperty("MetaDataRepository", "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); PCEnhancer.run(null, opts); diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/idtool/RecordsPerYear.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/idtool/RecordsPerYear.java new file mode 100644 index 000000000..0cbeb5c2c --- /dev/null +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/idtool/RecordsPerYear.java @@ -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; + } +} diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/idtool/TestApplicationIdTool.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/idtool/TestApplicationIdTool.java new file mode 100644 index 000000000..62af2914b --- /dev/null +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/idtool/TestApplicationIdTool.java @@ -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)); + } +} diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/common/apps/AutoIncrementPC3.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/common/apps/AutoIncrementPC3.java index 7de213c19..05751ecf8 100644 --- a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/common/apps/AutoIncrementPC3.java +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/common/apps/AutoIncrementPC3.java @@ -41,70 +41,71 @@ import jakarta.persistence.Table; @Table(name="AUTOINCPC3") public class AutoIncrementPC3 { - @Id - private long id = 0; + @Id + private long id = 0; + private Set setField = new HashSet (); - @Column(name="strngfld", length=50) - private String stringField = null; + @Column(name="strngfld", length=50) + private String stringField = null; - @OneToOne(cascade={CascadeType.PERSIST, CascadeType.REMOVE}) - private AutoIncrementPC3 oneOne = null; + @OneToOne(cascade={CascadeType.PERSIST, CascadeType.REMOVE}) + private AutoIncrementPC3 oneOne = null; - public AutoIncrementPC3() - { - } + public AutoIncrementPC3() + { + } - public AutoIncrementPC3(int id) - { - this.id = id; - } + public AutoIncrementPC3(int id) + { + this.id = id; + } - public long getId () - { - return this.id; - } + public long getId () + { + return this.id; + } - public void setId (long id) - { - this.id = id; - } + public void setId (long id) + { + this.id = id; + } - public Set getSetField () - { - return this.setField; - } + public Set getSetField () + { + return this.setField; + } - public void setSetField (Set setField) - { - this.setField = setField; - } + public void setSetField (Set setField) + { + this.setField = setField; + } - public String getStringField () - { - return this.stringField; - } + public String getStringField () + { + return this.stringField; + } - public void setStringField (String stringField) - { - this.stringField = stringField; - } + public void setStringField (String stringField) + { + this.stringField = stringField; + } - public AutoIncrementPC3 getOneOne () - { - return this.oneOne; - } + public AutoIncrementPC3 getOneOne () + { + return this.oneOne; + } - public void setOneOne (AutoIncrementPC3 oneOne) - { - this.oneOne = oneOne; - } + public void setOneOne (AutoIncrementPC3 oneOne) + { + this.oneOne = oneOne; + } }