Author: rmannibucau Date: Fri Jan 29 10:36:53 2016 New Revision: 1727520 URL: http://svn.apache.org/viewvc?rev=1727520&view=rev Log: OPENJPA-2626 support of java 8 bytecode test for isEnhanced - avoid to have logs full of exception/warnings when it actually works cause it is already enahnced at build time
Added: openjpa/trunk/openjpa-kernel/src/test/java/org/apache/openjpa/enhance/TestAsmAdaptor.java Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/AsmAdaptor.java openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/PCClassFileTransformer.java Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/AsmAdaptor.java URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/AsmAdaptor.java?rev=1727520&r1=1727519&r2=1727520&view=diff ============================================================================== --- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/AsmAdaptor.java (original) +++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/AsmAdaptor.java Fri Jan 29 10:36:53 2016 @@ -20,22 +20,29 @@ package org.apache.openjpa.enhance; import java.io.BufferedInputStream; import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; +import java.io.InputStream; import java.io.OutputStream; import java.net.URLDecoder; import org.apache.xbean.asm5.ClassReader; +import org.apache.xbean.asm5.ClassVisitor; import org.apache.xbean.asm5.ClassWriter; +import org.apache.xbean.asm5.Opcodes; import serp.bytecode.BCClass; +import static java.util.Arrays.asList; + /** * Use ASM to add required StackMapTable attribute to the byte code generated by * Serp. */ public final class AsmAdaptor { + private static final boolean USE_ASM = System.getProperty("java.version").compareTo("1.6") > 0; private static final int Java7_MajorVersion = 51; @SuppressWarnings("deprecation") @@ -95,6 +102,70 @@ public final class AsmAdaptor { return cw.toByteArray(); } + public static boolean use() + { + return USE_ASM; + } + + public static boolean isEnhanced(final byte[] b) + { + if (b == null) + { + return false; + } + final ClassReader cr = new ClassReader(b); + try + { + cr.accept(new ClassVisitor(Opcodes.ASM5) + { + @Override + public void visit(final int i, final int i1, + final String name, final String s, + final String parent, final String[] interfaces) + { + boolean enhanced = interfaces != null && interfaces.length > 0 && + asList(interfaces).contains("org/apache/openjpa/enhance/PersistenceCapable"); + if (!enhanced && name != null && parent != null && + !"java/lang/Object".equals(parent) && !name.equals(parent)) { + enhanced = isEnhanced(bytes(parent)); + } + throw new EnhancedStatusException(enhanced); + } + }, 0); + return false; + } catch (final EnhancedStatusException e) { + return e.status; + } catch (final Exception e) { + return false; + } + } + + private static byte[] bytes(final String type) + { + final ByteArrayOutputStream baos = new ByteArrayOutputStream(1024); + final InputStream stream = Thread.currentThread().getContextClassLoader() + .getResourceAsStream(type + ".class"); + if (stream == null) { + return null; + } + try { + int c; + byte[] buffer = new byte[1024]; + while ((c = stream.read(buffer)) >= 0) { + baos.write(buffer, 0, c); + } + } catch (IOException e) { + return null; + } finally { + try { + stream.close(); + } catch (IOException e) { + // no-op + } + } + return baos.toByteArray(); + } + private static class BCClassWriter extends ClassWriter { private final ClassLoader _loader; @@ -128,4 +199,12 @@ public final class AsmAdaptor { return class1.getName().replace('.', '/'); } } + + private static class EnhancedStatusException extends RuntimeException { + private final boolean status; + + private EnhancedStatusException(final boolean status) { + this.status = status; + } + } } Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/PCClassFileTransformer.java URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/PCClassFileTransformer.java?rev=1727520&r1=1727519&r2=1727520&view=diff ============================================================================== --- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/PCClassFileTransformer.java (original) +++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/PCClassFileTransformer.java Fri Jan 29 10:36:53 2016 @@ -37,6 +37,8 @@ import serp.bytecode.BCClass; import serp.bytecode.Project; import serp.bytecode.lowlevel.ConstantPoolTable; +import static com.sun.xml.internal.fastinfoset.alphabet.BuiltInRestrictedAlphabets.table; + /** * Transformer that makes persistent classes implement the * {@link PersistenceCapable} interface at runtime. @@ -227,6 +229,11 @@ public class PCClassFileTransformer * {@link PersistenceCapable}. */ private static boolean isEnhanced(byte[] b) { + if (AsmAdaptor.use()) + { + return AsmAdaptor.isEnhanced(b); + } + ConstantPoolTable table = new ConstantPoolTable(b); int idx = table.getEndIndex(); Added: openjpa/trunk/openjpa-kernel/src/test/java/org/apache/openjpa/enhance/TestAsmAdaptor.java URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/test/java/org/apache/openjpa/enhance/TestAsmAdaptor.java?rev=1727520&view=auto ============================================================================== --- openjpa/trunk/openjpa-kernel/src/test/java/org/apache/openjpa/enhance/TestAsmAdaptor.java (added) +++ openjpa/trunk/openjpa-kernel/src/test/java/org/apache/openjpa/enhance/TestAsmAdaptor.java Fri Jan 29 10:36:53 2016 @@ -0,0 +1,249 @@ +/* + * 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; + +import org.junit.Test; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +public class TestAsmAdaptor +{ + @Test + public void isEnhanced() + { + if (!AsmAdaptor.use()) + { + return; + } + assertTrue(AsmAdaptor.isEnhanced(bytes(Enhanced.class))); + assertTrue(AsmAdaptor.isEnhanced(bytes(TransitivelyEnhanced.class))); + assertFalse(AsmAdaptor.isEnhanced(bytes(NotEnhanced.class))); + } + + private byte[] bytes(final Class<?> type) + { + final ByteArrayOutputStream baos = new ByteArrayOutputStream(1024); + final InputStream stream = Thread.currentThread().getContextClassLoader() + .getResourceAsStream(type.getName().replace('.', '/') + ".class"); + try + { + int c; + byte[] buffer = new byte[1024]; + while ((c = stream.read(buffer)) >= 0) + { + baos.write(buffer, 0, c); + } + } + catch (IOException e) + { + fail(e.getMessage()); + } + finally + { + try + { + stream.close(); + } + catch (IOException e) + { + // no-op + } + } + return baos.toByteArray(); + } + + public static class NotEnhanced + { + } + + public static class TransitivelyEnhanced extends Enhanced + { + } + + public static class Enhanced implements PersistenceCapable // just a mock for the test + { + @Override + public int pcGetEnhancementContractVersion() + { + return 0; + } + + @Override + public Object pcGetGenericContext() + { + return null; + } + + @Override + public StateManager pcGetStateManager() + { + return null; + } + + @Override + public void pcReplaceStateManager(StateManager sm) + { + + } + + @Override + public void pcProvideField(int fieldIndex) + { + + } + + @Override + public void pcProvideFields(int[] fieldIndices) + { + + } + + @Override + public void pcReplaceField(int fieldIndex) + { + + } + + @Override + public void pcReplaceFields(int[] fieldIndex) + { + + } + + @Override + public void pcCopyFields(Object fromObject, int[] fields) + { + + } + + @Override + public void pcDirty(String fieldName) + { + + } + + @Override + public Object pcFetchObjectId() + { + return null; + } + + @Override + public Object pcGetVersion() + { + return null; + } + + @Override + public boolean pcIsDirty() + { + return false; + } + + @Override + public boolean pcIsTransactional() + { + return false; + } + + @Override + public boolean pcIsPersistent() + { + return false; + } + + @Override + public boolean pcIsNew() + { + return false; + } + + @Override + public boolean pcIsDeleted() + { + return false; + } + + @Override + public Boolean pcIsDetached() + { + return null; + } + + @Override + public PersistenceCapable pcNewInstance(StateManager sm, boolean clear) + { + return null; + } + + @Override + public PersistenceCapable pcNewInstance(StateManager sm, Object obj, boolean clear) + { + return null; + } + + @Override + public Object pcNewObjectIdInstance() + { + return null; + } + + @Override + public Object pcNewObjectIdInstance(Object obj) + { + return null; + } + + @Override + public void pcCopyKeyFieldsToObjectId(Object obj) + { + + } + + @Override + public void pcCopyKeyFieldsToObjectId(FieldSupplier supplier, Object obj) + { + + } + + @Override + public void pcCopyKeyFieldsFromObjectId(FieldConsumer consumer, Object obj) + { + + } + + @Override + public Object pcGetDetachedState() + { + return null; + } + + @Override + public void pcSetDetachedState(Object state) + { + + } + } +}