mirror of
https://github.com/apache/openjpa.git
synced 2025-02-20 17:05:15 +00:00
OPENJPA-2809 adding openjpa-junit5 module
This commit is contained in:
parent
44c4d8dc02
commit
ae9b2a904b
@ -38,8 +38,6 @@
|
||||
<description>Apache OpenJPA Examples - image-gallery</description>
|
||||
|
||||
<properties>
|
||||
<checkstyle.config.location>${project.basedir}${file.separator}..${file.separator}..${file.separator}openjpa-project${file.separator}checkstyle.xml</checkstyle.config.location>
|
||||
<checkstyle.suppressions.location>${project.basedir}${file.separator}..${file.separator}..${file.separator}openjpa-project${file.separator}suppressions.xml</checkstyle.suppressions.location>
|
||||
<test.jvm.maxpermsize>256m</test.jvm.maxpermsize>
|
||||
<test.jvm.maxheapsize>1024m</test.jvm.maxheapsize>
|
||||
<test.jvm.arguments>-Xmx${test.jvm.maxheapsize}</test.jvm.arguments>
|
||||
|
@ -40,7 +40,6 @@
|
||||
<description>Apache OpenJPA Examples - OpenBooks</description>
|
||||
|
||||
<properties>
|
||||
<checkstyle.config.location>${project.basedir}${file.separator}..${file.separator}..${file.separator}openjpa-project${file.separator}checkstyle.xml</checkstyle.config.location>
|
||||
<checkstyle.suppressions.location>${project.basedir}${file.separator}..${file.separator}..${file.separator}openjpa-project${file.separator}suppressions.xml</checkstyle.suppressions.location>
|
||||
<automatic-module-name>org.apache.openjpa.examples.openbooks</automatic-module-name>
|
||||
</properties>
|
||||
|
@ -39,8 +39,7 @@
|
||||
|
||||
<properties>
|
||||
<openjpa.Log>DefaultLevel=WARN</openjpa.Log>
|
||||
<checkstyle.config.location>${project.basedir}${file.separator}..${file.separator}openjpa-project${file.separator}checkstyle.xml</checkstyle.config.location>
|
||||
<checkstyle.suppressions.location>${project.basedir}${file.separator}..${file.separator}openjpa-project${file.separator}suppressions.xml</checkstyle.suppressions.location>
|
||||
<checkstyle.suppressions.location>${project.basedir}${file.separator}..${file.separator}..${file.separator}openjpa-project${file.separator}suppressions.xml</checkstyle.suppressions.location>
|
||||
</properties>
|
||||
|
||||
<modules>
|
||||
|
@ -47,7 +47,6 @@
|
||||
</dependencies>
|
||||
|
||||
<properties>
|
||||
<checkstyle.config.location>${project.basedir}${file.separator}..${file.separator}..${file.separator}openjpa-project${file.separator}checkstyle.xml</checkstyle.config.location>
|
||||
<checkstyle.suppressions.location>${project.basedir}${file.separator}..${file.separator}..${file.separator}openjpa-project${file.separator}suppressions.xml</checkstyle.suppressions.location>
|
||||
<automatic-module-name>org.apache.openjpa.examples.simple</automatic-module-name>
|
||||
</properties>
|
||||
|
@ -25,10 +25,10 @@
|
||||
<bundle dependency="true">mvn:org.apache.geronimo.specs/geronimo-annotation_1.0_spec/1.1.1</bundle>
|
||||
<bundle dependency="true">mvn:org.apache.geronimo.specs/geronimo-el_1.0_spec/1.0.1</bundle>
|
||||
<bundle dependency="true">mvn:org.apache.commons/commons-pool2/2.6.0</bundle>
|
||||
<bundle dependency="true">mvn:org.apache.commons/commons-dbcp2/2.6.0</bundle>
|
||||
<bundle dependency="true">mvn:org.apache.commons/commons-collections4/4.3</bundle>
|
||||
<bundle dependency="true">mvn:org.apache.commons/commons-dbcp2/2.7.0</bundle>
|
||||
<bundle dependency="true">mvn:org.apache.commons/commons-collections4/4.4</bundle>
|
||||
<bundle dependency="true">mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.serp/1.14.1_1</bundle>
|
||||
<bundle dependency="true">mvn:org.apache.xbean/xbean-asm7-shaded/4.12</bundle>
|
||||
<bundle dependency="true">mvn:org.apache.xbean/xbean-asm7-shaded/${xbean.version}</bundle>
|
||||
<bundle>mvn:org.apache.openjpa/openjpa/${project.version}</bundle>
|
||||
<capability>
|
||||
osgi.service;objectClass=javax.persistence.spi.PersistenceProvider;effective:=active;javax.persistence.provider=org.apache.openjpa.persistence.PersistenceProviderImpl
|
||||
|
@ -36,8 +36,6 @@
|
||||
<description>OpenJPA Integration Tests - Daytrader</description>
|
||||
|
||||
<properties>
|
||||
<checkstyle.config.location>${project.basedir}${file.separator}..${file.separator}..${file.separator}openjpa-project${file.separator}checkstyle.xml</checkstyle.config.location>
|
||||
<checkstyle.suppressions.location>${project.basedir}${file.separator}..${file.separator}..${file.separator}openjpa-project${file.separator}suppressions.xml</checkstyle.suppressions.location>
|
||||
<daytrader.version>2.2-SNAPSHOT</daytrader.version>
|
||||
<dbcp.maxTotal>10</dbcp.maxTotal>
|
||||
<dbcp.maxIdle>5</dbcp.maxIdle>
|
||||
|
@ -45,9 +45,6 @@
|
||||
<name>OpenJPA Integration Tests - Examples</name>
|
||||
<description>OpenJPA Integration Tests - Examples</description>
|
||||
|
||||
<properties>
|
||||
<checkstyle.config.location>${project.basedir}${file.separator}..${file.separator}..${file.separator}openjpa-project${file.separator}checkstyle.xml</checkstyle.config.location>
|
||||
</properties>
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>examples-profile</id>
|
||||
|
@ -37,8 +37,6 @@
|
||||
<description>OpenJPA Integration Tests - JMX Platform MBeans</description>
|
||||
|
||||
<properties>
|
||||
<checkstyle.config.location>${project.basedir}${file.separator}..${file.separator}..${file.separator}openjpa-project${file.separator}checkstyle.xml</checkstyle.config.location>
|
||||
<checkstyle.suppressions.location>${project.basedir}${file.separator}..${file.separator}..${file.separator}openjpa-project${file.separator}suppressions.xml</checkstyle.suppressions.location>
|
||||
<!-- Enable the JMX platform MBean provider -->
|
||||
<test.jvm.jmxprovider>com.sun.management.jmxremote</test.jvm.jmxprovider>
|
||||
<!-- Disable JMX platform MBean authentication -->
|
||||
|
@ -36,8 +36,6 @@
|
||||
<description>OpenJPA Integration Tests - SLF4JLogFactory</description>
|
||||
|
||||
<properties>
|
||||
<checkstyle.config.location>${project.basedir}${file.separator}..${file.separator}..${file.separator}openjpa-project${file.separator}checkstyle.xml</checkstyle.config.location>
|
||||
<checkstyle.suppressions.location>${project.basedir}${file.separator}..${file.separator}..${file.separator}openjpa-project${file.separator}suppressions.xml</checkstyle.suppressions.location>
|
||||
<!-- use SLF4JLogFactory for logging -->
|
||||
<openjpa.Log>slf4j</openjpa.Log>
|
||||
<automatic-module-name>org.apache.openjpa.integration.slf4j</automatic-module-name>
|
||||
|
@ -87,7 +87,6 @@
|
||||
<description>OpenJPA Integration Tests - JPA TCK</description>
|
||||
|
||||
<properties>
|
||||
<checkstyle.config.location>${project.basedir}${file.separator}..${file.separator}..${file.separator}openjpa-project${file.separator}checkstyle.xml</checkstyle.config.location>
|
||||
<tck2.level>20110815</tck2.level>
|
||||
</properties>
|
||||
<profiles>
|
||||
|
@ -36,7 +36,6 @@
|
||||
<description>OpenJPA Integration Tests - Bean Validation</description>
|
||||
|
||||
<properties>
|
||||
<checkstyle.config.location>${project.basedir}${file.separator}..${file.separator}..${file.separator}openjpa-project${file.separator}checkstyle.xml</checkstyle.config.location>
|
||||
<checkstyle.suppressions.location>${project.basedir}${file.separator}..${file.separator}..${file.separator}openjpa-project${file.separator}suppressions.xml</checkstyle.suppressions.location>
|
||||
<automatic-module-name>org.apache.openjpa.integration.validation</automatic-module-name>
|
||||
</properties>
|
||||
|
62
openjpa-junit5/pom.xml
Normal file
62
openjpa-junit5/pom.xml
Normal file
@ -0,0 +1,62 @@
|
||||
<?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.
|
||||
-->
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>org.apache.openjpa</groupId>
|
||||
<artifactId>openjpa-parent</artifactId>
|
||||
<version>3.0.1-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>openjpa-junit5</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>OpenJPA JUnit 5</name>
|
||||
<description>OpenJPA JUnit 5</description>
|
||||
|
||||
<properties>
|
||||
<automatic-module-name>org.apache.openjpa.junit5</automatic-module-name>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.apache.geronimo.specs</groupId>
|
||||
<artifactId>geronimo-jpa_2.1_spec</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.openjpa</groupId>
|
||||
<artifactId>openjpa</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency> <!-- only for auto mode, can be excluded if not used -->
|
||||
<groupId>org.apache.xbean</groupId>
|
||||
<artifactId>xbean-finder</artifactId>
|
||||
<version>${xbean.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter</artifactId>
|
||||
<version>5.6.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
@ -0,0 +1,57 @@
|
||||
/*
|
||||
* 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.junit5;
|
||||
|
||||
import org.apache.openjpa.junit5.internal.OpenJPAExtension;
|
||||
import org.apache.openjpa.lib.log.LogFactory;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import static java.lang.annotation.ElementType.TYPE;
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
|
||||
/**
|
||||
* Enables <b>in place</b> enhancement for entities listed or found by scanning in test classpath.
|
||||
* It enables to run tests from the IDE with enhancement.
|
||||
*
|
||||
* WARNING: if you use that for tests but don't want to enhance your entities, ensure to clean+recompile them
|
||||
* after tests otherwise you will have entities depending on OpenJPA at bytecode level.
|
||||
*/
|
||||
@Target(TYPE)
|
||||
@Retention(RUNTIME)
|
||||
@ExtendWith(OpenJPAExtension.class)
|
||||
public @interface OpenJPASupport {
|
||||
/**
|
||||
* @return the list of class names (don't use {@code MyEntity.class}) to enhance if {@code auto} is false.
|
||||
*/
|
||||
String[] entities() default {};
|
||||
|
||||
/**
|
||||
* @return if true, only directories in the classpath will be browsed to enhance entities,
|
||||
* if false {@link OpenJPASupport#entities()} will be used.
|
||||
*/
|
||||
boolean auto() default true;
|
||||
|
||||
/**
|
||||
* @return the log factory to use, if not set slf4j will be tried and if it fails will fallback on the default one.
|
||||
*/
|
||||
Class<?> logFactory() default LogFactory.class;
|
||||
}
|
@ -0,0 +1,346 @@
|
||||
/*
|
||||
* 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.junit5.internal;
|
||||
|
||||
import org.apache.openjpa.conf.OpenJPAConfigurationImpl;
|
||||
import org.apache.openjpa.enhance.AsmAdaptor;
|
||||
import org.apache.openjpa.enhance.PCEnhancer;
|
||||
import org.apache.openjpa.enhance.PersistenceCapable;
|
||||
import org.apache.openjpa.junit5.OpenJPASupport;
|
||||
import org.apache.openjpa.lib.log.LogFactory;
|
||||
import org.apache.openjpa.lib.log.LogFactoryImpl;
|
||||
import org.apache.openjpa.lib.log.SLF4JLogFactory;
|
||||
import org.apache.openjpa.meta.MetaDataRepository;
|
||||
import org.apache.openjpa.persistence.PersistenceMetaDataFactory;
|
||||
import org.apache.xbean.asm7.AnnotationVisitor;
|
||||
import org.apache.xbean.asm7.ClassReader;
|
||||
import org.apache.xbean.asm7.Type;
|
||||
import org.apache.xbean.asm7.shade.commons.EmptyVisitor;
|
||||
import org.apache.xbean.finder.ClassLoaders;
|
||||
import org.junit.jupiter.api.extension.BeforeAllCallback;
|
||||
import org.junit.jupiter.api.extension.ExtensionContext;
|
||||
import org.junit.platform.commons.util.AnnotationUtils;
|
||||
import serp.bytecode.BCClass;
|
||||
import serp.bytecode.Project;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.MappedSuperclass;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.net.URL;
|
||||
import java.nio.file.FileVisitResult;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.SimpleFileVisitor;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
import static org.apache.xbean.asm7.ClassReader.SKIP_CODE;
|
||||
import static org.apache.xbean.asm7.ClassReader.SKIP_DEBUG;
|
||||
import static org.apache.xbean.asm7.ClassReader.SKIP_FRAMES;
|
||||
|
||||
public class OpenJPAExtension implements BeforeAllCallback {
|
||||
private static final Logger LOGGER = Logger.getLogger(OpenJPAExtension.class.getName());
|
||||
|
||||
@Override
|
||||
public void beforeAll(final ExtensionContext context) {
|
||||
AnnotationUtils.findAnnotation(context.getElement(), OpenJPASupport.class).ifPresent(s -> {
|
||||
final ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
|
||||
final OpenJpaClassLoader enhancementClassLoader = new OpenJpaClassLoader(
|
||||
classLoader, createLogFactory(classLoader, s.logFactory()));
|
||||
final Thread thread = Thread.currentThread();
|
||||
thread.setContextClassLoader(enhancementClassLoader);
|
||||
try {
|
||||
if (s.auto()) {
|
||||
try {
|
||||
ClassLoaders.findUrls(enhancementClassLoader.getParent()).stream()
|
||||
.map(org.apache.xbean.finder.util.Files::toFile)
|
||||
.filter(File::isDirectory)
|
||||
.map(File::toPath)
|
||||
.forEach(dir -> {
|
||||
LOGGER.fine(() -> "Enhancing folder '" + dir + "'");
|
||||
try {
|
||||
enhanceDirectory(enhancementClassLoader, dir);
|
||||
} catch (final IOException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
});
|
||||
} catch (final IOException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
} else {
|
||||
Stream.of(s.entities()).forEach(e -> {
|
||||
try {
|
||||
enhancementClassLoader.loadClass(e);
|
||||
} catch (final ClassNotFoundException e1) {
|
||||
throw new IllegalArgumentException(e1);
|
||||
}
|
||||
});
|
||||
}
|
||||
} finally {
|
||||
thread.setContextClassLoader(enhancementClassLoader.getParent());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private LogFactory createLogFactory(final ClassLoader classLoader, final Class<?> logFactory) {
|
||||
try {
|
||||
if (logFactory == LogFactory.class) {
|
||||
try {
|
||||
return new SLF4JLogFactory();
|
||||
} catch (final Error | Exception e) {
|
||||
return new LogFactoryImpl();
|
||||
}
|
||||
}
|
||||
return logFactory.asSubclass(LogFactory.class).getConstructor().newInstance();
|
||||
} catch (final RuntimeException e) {
|
||||
throw e;
|
||||
} catch (final Exception e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void enhanceDirectory(final OpenJpaClassLoader enhancementClassLoader, final Path dir) throws IOException {
|
||||
Files.walkFileTree(dir, new SimpleFileVisitor<Path>() {
|
||||
@Override
|
||||
public FileVisitResult visitFile(final Path file, final BasicFileAttributes attrs) throws IOException {
|
||||
if (file.getFileName().toString().endsWith(".class")) {
|
||||
final String relativeName = dir.relativize(file).toString();
|
||||
try {
|
||||
enhancementClassLoader.handleEnhancement(
|
||||
relativeName.substring(0, relativeName.length() - ".class".length()));
|
||||
} catch (final ClassNotFoundException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
return super.visitFile(file, attrs);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static abstract class BaseClassLoader extends ClassLoader {
|
||||
private BaseClassLoader(final ClassLoader parent) {
|
||||
super(parent);
|
||||
}
|
||||
|
||||
protected abstract Class<?> doLoadClass(String name, boolean resolve) throws ClassNotFoundException;
|
||||
|
||||
@Override
|
||||
protected Class<?> loadClass(final String name, final boolean resolve) throws ClassNotFoundException {
|
||||
if (name != null && !name.startsWith("java") && !name.startsWith("sun") && !name.startsWith("jdk")) {
|
||||
return doLoadClass(name, resolve);
|
||||
}
|
||||
return defaultLoadClass(name, resolve);
|
||||
}
|
||||
|
||||
protected Class<?> defaultLoadClass(final String name, final boolean resolve) throws ClassNotFoundException {
|
||||
return super.loadClass(name, resolve);
|
||||
}
|
||||
|
||||
protected byte[] loadBytes(final String name) {
|
||||
final URL url = findUrl(name);
|
||||
if (url == null || "jar".equals(url.getProtocol()) /*assume done in build*/) {
|
||||
return null;
|
||||
}
|
||||
byte[] buffer = new byte[4096];
|
||||
final ByteArrayOutputStream inMem = new ByteArrayOutputStream(buffer.length);
|
||||
try (final InputStream is = url.openStream()) {
|
||||
int read;
|
||||
while ((read = is.read(buffer)) >= 0) {
|
||||
if (read > 0) {
|
||||
inMem.write(buffer, 0, read);
|
||||
}
|
||||
}
|
||||
} catch (final IOException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
return inMem.toByteArray();
|
||||
}
|
||||
|
||||
protected URL findUrl(final String name) {
|
||||
return getResource(name.replace('.', '/') + ".class");
|
||||
}
|
||||
}
|
||||
|
||||
private static class OpenJpaClassLoader extends BaseClassLoader {
|
||||
private static final String PERSITENCE_CAPABLE = Type.getDescriptor(PersistenceCapable.class);
|
||||
private static final String ENTITY = Type.getDescriptor(Entity.class);
|
||||
private static final String MAPPED_SUPERCLASS = Type.getDescriptor(MappedSuperclass.class);
|
||||
|
||||
private final MetaDataRepository repos;
|
||||
private final ClassLoader tmpLoader;
|
||||
private final Collection<String> alreadyEnhanced = new ArrayList<>();
|
||||
|
||||
private OpenJpaClassLoader(final ClassLoader parent, final LogFactory logFactory) {
|
||||
super(parent);
|
||||
|
||||
final OpenJPAConfigurationImpl conf = new OpenJPAConfigurationImpl();
|
||||
conf.setLogFactory(logFactory);
|
||||
|
||||
tmpLoader = new CompanionLoader(parent);
|
||||
repos = new MetaDataRepository();
|
||||
repos.setConfiguration(conf);
|
||||
repos.setMetaDataFactory(new PersistenceMetaDataFactory());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected synchronized Class<?> doLoadClass(final String name, final boolean resolve) throws ClassNotFoundException {
|
||||
final Class<?> clazz = findLoadedClass(name);
|
||||
if (clazz != null) {
|
||||
if (resolve) {
|
||||
resolveClass(clazz);
|
||||
}
|
||||
return clazz;
|
||||
}
|
||||
handleEnhancement(name);
|
||||
return defaultLoadClass(name, resolve);
|
||||
}
|
||||
|
||||
private void handleEnhancement(final String name) throws ClassNotFoundException {
|
||||
final byte[] enhanced = ensureEnhancedIfNeeded(name);
|
||||
if (enhanced != null && alreadyEnhanced.add(name)) {
|
||||
// we could do that but test classes will be loaded with parent loader
|
||||
// so just rewrite the class on the fly assuming it was not yet read
|
||||
try {
|
||||
Files.write(findTarget(name), enhanced, StandardOpenOption.TRUNCATE_EXISTING);
|
||||
LOGGER.info(() -> "Enhanced '" + name + "'");
|
||||
} catch (final IOException e) {
|
||||
throw new ClassNotFoundException(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Path findTarget(final String name) {
|
||||
final URL url = findUrl(name);
|
||||
if (!"file".equals(url.getProtocol())) {
|
||||
throw new IllegalStateException("Only file urls are supported today: " + url);
|
||||
}
|
||||
return Paths.get(url.getPath());
|
||||
}
|
||||
|
||||
private byte[] enhance(final byte[] classBytes) {
|
||||
final Thread thread = Thread.currentThread();
|
||||
final ClassLoader old = thread.getContextClassLoader();
|
||||
thread.setContextClassLoader(tmpLoader);
|
||||
try (final InputStream stream = new ByteArrayInputStream(classBytes)) {
|
||||
final PCEnhancer enhancer = new PCEnhancer(
|
||||
repos.getConfiguration(),
|
||||
new Project().loadClass(stream, tmpLoader),
|
||||
repos, tmpLoader);
|
||||
if (enhancer.run() == PCEnhancer.ENHANCE_NONE) {
|
||||
return null;
|
||||
}
|
||||
final BCClass pcb = enhancer.getPCBytecode();
|
||||
return AsmAdaptor.toByteArray(pcb, pcb.toByteArray());
|
||||
} catch (final IOException e) {
|
||||
throw new IllegalStateException(e);
|
||||
} finally {
|
||||
thread.setContextClassLoader(old);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isJpaButNotEnhanced(final byte[] classBytes) {
|
||||
try (final InputStream stream = new ByteArrayInputStream(classBytes)) {
|
||||
final ClassReader reader = new ClassReader(stream);
|
||||
reader.accept(new EmptyVisitor() {
|
||||
@Override
|
||||
public void visit(final int version, final int access, final String name,
|
||||
final String signature, final String superName, final String[] interfaces) {
|
||||
if (interfaces != null && asList(interfaces).contains(PERSITENCE_CAPABLE)) {
|
||||
throw new AlreadyEnhanced(); // exit
|
||||
}
|
||||
super.visit(version, access, name, signature, superName, interfaces);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
|
||||
if (ENTITY.equals(descriptor) || MAPPED_SUPERCLASS.equals(descriptor)) {
|
||||
throw new MissingEnhancement(); // we already went into visit() so we miss the enhancement
|
||||
}
|
||||
return new EmptyVisitor().visitAnnotation(descriptor, visible);
|
||||
}
|
||||
}, SKIP_DEBUG + SKIP_CODE + SKIP_FRAMES);
|
||||
return false;
|
||||
} catch (final IOException e) {
|
||||
throw new IllegalStateException(e);
|
||||
} catch (final AlreadyEnhanced alreadyEnhanced) {
|
||||
return false;
|
||||
} catch (final MissingEnhancement alreadyEnhanced) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] ensureEnhancedIfNeeded(final String name) {
|
||||
final byte[] classBytes = loadBytes(name);
|
||||
if (classBytes == null) {
|
||||
return null;
|
||||
}
|
||||
if (isJpaButNotEnhanced(classBytes)) {
|
||||
final byte[] enhanced = enhance(classBytes);
|
||||
if (enhanced != null) {
|
||||
return enhanced;
|
||||
}
|
||||
LOGGER.info("'" + name + "' already enhanced");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static class CompanionLoader extends BaseClassLoader {
|
||||
private CompanionLoader(final ClassLoader parent) {
|
||||
super(parent);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<?> doLoadClass(final String name, final boolean resolve) throws ClassNotFoundException {
|
||||
final Class<?> clazz = findLoadedClass(name);
|
||||
if (clazz != null) {
|
||||
if (resolve) {
|
||||
resolveClass(clazz);
|
||||
}
|
||||
return clazz;
|
||||
}
|
||||
final byte[] content = loadBytes(name);
|
||||
if (content != null) {
|
||||
final Class<?> value = super.defineClass(name, content, 0, content.length);
|
||||
if (resolve) {
|
||||
resolveClass(value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
return defaultLoadClass(name, resolve);
|
||||
}
|
||||
}
|
||||
|
||||
private static class MissingEnhancement extends RuntimeException {
|
||||
}
|
||||
|
||||
private static class AlreadyEnhanced extends RuntimeException {
|
||||
}
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* 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.junit5;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
|
||||
@Entity
|
||||
public class MyEntity {
|
||||
@Id
|
||||
private long id;
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* 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.junit5;
|
||||
|
||||
import org.apache.openjpa.enhance.PersistenceCapable;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
@OpenJPASupport
|
||||
class OpenJPASupportTest {
|
||||
@Test
|
||||
void ensureEnhanced() {
|
||||
assertTrue(PersistenceCapable.class.isAssignableFrom(MyEntity.class));
|
||||
}
|
||||
}
|
@ -78,7 +78,7 @@
|
||||
<dependency>
|
||||
<groupId>org.apache.xbean</groupId>
|
||||
<artifactId>xbean-asm7-shaded</artifactId>
|
||||
<version>4.12</version>
|
||||
<version>${xbean.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
|
@ -21,21 +21,23 @@
|
||||
<module name="NewlineAtEndOfFile">
|
||||
<property name="lineSeparator" value="lf"/>
|
||||
</module>
|
||||
<module name="LineLength">
|
||||
<property name="max" value="150"/>
|
||||
</module>
|
||||
<module name="TreeWalker">
|
||||
<module name="FileContentsHolder"/>
|
||||
<module name="LineLength">
|
||||
<property name="max" value="150"/>
|
||||
</module>
|
||||
<module name="RegexpSinglelineJava">
|
||||
<property name="format" value="System\.(out|err)\.print(ln)?\("/>
|
||||
<property name="ignoreComments" value="true"/>
|
||||
</module>
|
||||
</module>
|
||||
<module name="SuppressionCommentFilter">
|
||||
<property name="offCommentFormat" value="// START - ALLOW PRINT STATEMENTS"/>
|
||||
<property name="onCommentFormat" value="// STOP - ALLOW PRINT STATEMENTS"/>
|
||||
<module name="SuppressionCommentFilter">
|
||||
<property name="offCommentFormat" value="// START - ALLOW PRINT STATEMENTS"/>
|
||||
<property name="onCommentFormat" value="// STOP - ALLOW PRINT STATEMENTS"/>
|
||||
</module>
|
||||
</module>
|
||||
|
||||
<!-- File location is specified in root pom.xml via ${checkstyle.suppressions.location} -->
|
||||
<module name="SuppressionFilter"/>
|
||||
<module name="SuppressionFilter">
|
||||
<property name="file" value="${checkstyle.suppressions.location}"/>
|
||||
<property name="optional" value="true"/>
|
||||
</module>
|
||||
</module>
|
||||
|
@ -28,7 +28,6 @@
|
||||
<inceptionYear>2012</inceptionYear>
|
||||
|
||||
<properties>
|
||||
<checkstyle.config.location>${project.basedir}${file.separator}..${file.separator}..${file.separator}openjpa-project${file.separator}checkstyle.xml</checkstyle.config.location>
|
||||
<checkstyle.suppressions.location>${project.basedir}${file.separator}..${file.separator}..${file.separator}openjpa-project${file.separator}suppressions.xml</checkstyle.suppressions.location>
|
||||
<automatic-module-name>org.apache.openjpa.tools.statistics.was</automatic-module-name>
|
||||
</properties>
|
||||
|
@ -28,7 +28,6 @@
|
||||
<inceptionYear>2012</inceptionYear>
|
||||
|
||||
<properties>
|
||||
<checkstyle.config.location>${project.basedir}${file.separator}..${file.separator}..${file.separator}openjpa-project${file.separator}checkstyle.xml</checkstyle.config.location>
|
||||
<checkstyle.suppressions.location>${project.basedir}${file.separator}..${file.separator}..${file.separator}openjpa-project${file.separator}suppressions.xml</checkstyle.suppressions.location>
|
||||
<automatic-module-name>org.apache.openjpa.tools.statistics</automatic-module-name>
|
||||
</properties>
|
||||
|
@ -41,7 +41,6 @@
|
||||
</description>
|
||||
<inceptionYear>2011</inceptionYear>
|
||||
<properties>
|
||||
<checkstyle.config.location>${project.basedir}${file.separator}..${file.separator}..${file.separator}openjpa-project${file.separator}checkstyle.xml</checkstyle.config.location>
|
||||
<checkstyle.suppressions.location>${project.basedir}${file.separator}..${file.separator}..${file.separator}openjpa-project${file.separator}suppressions.xml</checkstyle.suppressions.location>
|
||||
<min.maven.version>3.3.9</min.maven.version>
|
||||
</properties>
|
||||
|
@ -36,10 +36,6 @@
|
||||
|
||||
<name>OpenJPA tools</name>
|
||||
|
||||
<properties>
|
||||
<checkstyle.config.location>${project.basedir}${file.separator}..${file.separator}openjpa-project${file.separator}checkstyle.xml</checkstyle.config.location>
|
||||
</properties>
|
||||
|
||||
<modules>
|
||||
<module>openjpa-maven-plugin</module>
|
||||
<module>openjpa-fetch-statistics</module>
|
||||
|
41
pom.xml
41
pom.xml
@ -47,7 +47,6 @@
|
||||
<openjpa.version>${project.version}</openjpa.version>
|
||||
<openjpa.Log>DefaultLevel=INFO</openjpa.Log>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<checkstyle.config.location>openjpa-project${file.separator}checkstyle.xml</checkstyle.config.location>
|
||||
<checkstyle.suppressions.location>openjpa-project${file.separator}suppressions.xml</checkstyle.suppressions.location>
|
||||
|
||||
<site.deploy.url>scp://people.apache.org/home/${site.deploy.user.name}/public_html/openjpa/${project.version}/staging-site</site.deploy.url>
|
||||
@ -93,8 +92,9 @@
|
||||
|
||||
<maven.javadoc.version>3.0.1</maven.javadoc.version>
|
||||
<javadoc.additionalparam />
|
||||
<maven.surefire.version>2.22.0</maven.surefire.version>
|
||||
<maven.surefire.version>3.0.0-M4</maven.surefire.version>
|
||||
|
||||
<xbean.version>4.16</xbean.version>
|
||||
<bval.version>1.1.2</bval.version>
|
||||
<jmock.version>2.9.0</jmock.version>
|
||||
<automatic-module-name>-SUBMODULES-NEED-TO-OVERRIDE-THIS-</automatic-module-name>
|
||||
@ -183,6 +183,7 @@
|
||||
<module>openjpa-all</module>
|
||||
<module>openjpa-tools</module>
|
||||
<module>openjpa-features</module>
|
||||
<module>openjpa-junit5</module>
|
||||
</modules>
|
||||
|
||||
<profiles>
|
||||
@ -1702,7 +1703,7 @@
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-collections4</artifactId>
|
||||
<version>4.3</version>
|
||||
<version>4.4</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.sourceforge.serp</groupId>
|
||||
@ -1718,7 +1719,7 @@
|
||||
<dependency>
|
||||
<groupId>org.apache.geronimo.specs</groupId>
|
||||
<artifactId>geronimo-jpa_2.2_spec</artifactId>
|
||||
<version>1.1-SNAPSHOT</version>
|
||||
<version>1.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.geronimo.specs</groupId>
|
||||
@ -1758,7 +1759,7 @@
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-dbcp2</artifactId>
|
||||
<version>2.6.0</version>
|
||||
<version>2.7.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.xml.bind</groupId>
|
||||
@ -2067,7 +2068,7 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-checkstyle-plugin</artifactId>
|
||||
<version>3.0.0</version>
|
||||
<version>3.1.1</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
@ -2322,6 +2323,34 @@
|
||||
<failsOnError>true</failsOnError>
|
||||
<consoleOutput>true</consoleOutput>
|
||||
<includeTestSourceDirectory>true</includeTestSourceDirectory>
|
||||
<excludes>**/*_.java</excludes>
|
||||
<logViolationsToConsole>true</logViolationsToConsole>
|
||||
<checkstyleRules>
|
||||
<module name="Checker">
|
||||
<module name="NewlineAtEndOfFile">
|
||||
<property name="lineSeparator" value="lf"/>
|
||||
</module>
|
||||
<module name="LineLength">
|
||||
<property name="max" value="150"/>
|
||||
</module>
|
||||
<module name="TreeWalker">
|
||||
<module name="RegexpSinglelineJava">
|
||||
<property name="format" value="System\.(out|err)\.print(ln)?\("/>
|
||||
<property name="ignoreComments" value="true"/>
|
||||
</module>
|
||||
<module name="SuppressionCommentFilter">
|
||||
<property name="offCommentFormat" value="// START - ALLOW PRINT STATEMENTS"/>
|
||||
<property name="onCommentFormat" value="// STOP - ALLOW PRINT STATEMENTS"/>
|
||||
</module>
|
||||
</module>
|
||||
|
||||
<!-- File location is specified in root pom.xml via ${checkstyle.suppressions.location} -->
|
||||
<module name="SuppressionFilter">
|
||||
<property name="file" value="${checkstyle.suppressions.location}"/>
|
||||
<property name="optional" value="true"/>
|
||||
</module>
|
||||
</module>
|
||||
</checkstyleRules>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
|
Loading…
x
Reference in New Issue
Block a user