Community
Participate
Working Groups
Build Identifier: 2.1.1.v20100817-r8050 I wrote a verbose description of our problem here: http://www.eclipse.org/forums/index.php?t=msg&th=175086&start=0&S=ba5ec765f86f8cbfd9bd40b431e06457 We obfuscate our jar with proguard (no classes that are used by eclipselink are obfuscated) and that leads to a problem reading in the annotations. I created a very small sample with three classes (which just creates a h2 in-memory db with three entities). A zipped workspace is attached to this bug report. I also attached the raw jar and the obfuscated one in another zip file. Decompiled with jd-gui the class TermEjb looks exactly the same in both versions. On byte code level there are a lot of differences, but it seems to be exactly the same java code. This is the problematic part of the TermEjb code: @JoinTable(name = "TERMEJB_CUSTOMFIELDVALUEEJB", joinColumns = @JoinColumn(name = "TERMEJB_ID"), inverseJoinColumns = @JoinColumn(name = "CUSTOMFIELDS_ID")) @ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.REMOVE}) //this line works after obfuscation //private Map<Integer, CustomFieldValueEjb> customFields; //this next two lines do not work after obfuscation @MapKey(name = "field") private Map<CustomFieldEjb, CustomFieldValueEjb> customFields; Reproducible: Always Steps to Reproduce: 1. unzip the attached file TestJarObfuscatedAndOriginal.zip 2. type java -jar derFetteMainer.jar to run the original jar. You will see a short sys-out message: DerFetteMainer ist am Start.... org.eclipse.persistence.internal.jpa.EntityManagerImpl@44b09697 DerFetteMainer hat funktioniert und ist fertig 3. Now try the same with the jar that was created by Proguard, by typing java -jar derFetteMainer_ob.jar. You will get a stack trace: DerFetteMainer ist am Start.... [EL Severe]: 2010-09-09 17:13:14.784--ServerSession(1373164447)--Local Exception Stack: Exception [EclipseLink-0] (Eclipse Persistence Services - 2.1.1.v20100817-r8050): org.eclipse.persistence.exceptions.Int egrityException Descriptor Exceptions: --------------------------------------------------------- Exception [EclipseLink-93] (Eclipse Persistence Services - 2.1.1.v20100817-r8050): org.eclipse.persistence.exceptions.De scriptorException Exception Description: The table [CUSTOMFIELDVALUEEJB] is not present in this descriptor. Descriptor: RelationalDescriptor(com.acrolinx.test.TermEjb --> [DatabaseTable(TERMEJB)]) Runtime Exceptions: --------------------------------------------------------- java.lang.IndexOutOfBoundsException: Index: 0, Size: 0 at org.eclipse.persistence.internal.sessions.DatabaseSessionImpl.initializeDescriptors(DatabaseSessionImpl.java: 471)
Created attachment 178527 [details] Original jar and the one written by Proguard (and three dependencies) 1. unzip the file 2. add EclipseLink 2.1 and javax_persistence in the "derFetteMainer_lib" folder 3. just execute the both jars two see the difference. - Original one "derFetteMainer.jar" executes fine, and prints three lines. - The one written by Proguard "derFetteMainer_ob.jar" throws an EL-93 exception.
Created attachment 178529 [details] The workspace for this simple test Complete workspace just add EclipseLink 2.1 and javax_persistence in the lib folder.
I found a workaround after stepping through asm and EclipseLink classes (it's horrible what's going on in the asm library. Why don't you use java reflection to get the annotations?!) It is possible to patch the method org.eclipse.persistence.internal.jpa.metadata.accessors.objects.MetadataAsmFactory.ClassMetadataVisitor.addAnnotations(Attribute, Map<String, MetadataAnnotation>) like this: /** * If the attribute is an annotations attribute, add all annotations attached to it. */ public void addAnnotations(final Attribute attr, final Map<String, MetadataAnnotation> annotations) { if (attr instanceof RuntimeVisibleAnnotations) { final RuntimeVisibleAnnotations visibleAnnotations = (RuntimeVisibleAnnotations) attr; for (final Iterator iterator = visibleAnnotations.annotations.iterator(); iterator.hasNext();) { final Annotation visibleAnnotation = (Annotation) iterator.next(); // Only add annotations that we care about. if ((visibleAnnotation.type.indexOf("javax/persistence") != -1) || (visibleAnnotation.type.indexOf("org/eclipse/persistence") != -1)) { final MetadataAnnotation annotation = buildAnnotation(visibleAnnotation); annotations.put(annotation.getName(), annotation); } } } //FIX: also read "sub-annotations" if ((attr != null && attr.next instanceof RuntimeVisibleAnnotations)) { final RuntimeVisibleAnnotations visibleAnnotations = (RuntimeVisibleAnnotations) attr.next; for (final Iterator iterator = visibleAnnotations.annotations.iterator(); iterator.hasNext();) { final Annotation visibleAnnotation = (Annotation) iterator.next(); // Only add annotations that we care about. if ((visibleAnnotation.type.indexOf("javax/persistence") != -1) || (visibleAnnotation.type.indexOf("org/eclipse/persistence") != -1)) { final MetadataAnnotation annotation = buildAnnotation(visibleAnnotation); if (!annotations.containsKey(annotation.getName())) { annotations.put(annotation.getName(), annotation); } } } } } But I think this is only a workaround and should be elaborated more precisely.
FYI: ASM is used to get annotations to avoid some needing a special classloader to introspect the classes.
Setting target and priority. See the following page for details of the meanings of these fields: http://wiki.eclipse.org/EclipseLink/Development/Bugs/Guidelines
Here is our version of a fix for this issue: Note that this is a bit different (and more robust) than Hans's solution, as it checks ALL of the Attributes in the hierarchy, instead of just the first two. We ran into an issue where there were many Annotations that needed to be saved. /** * If the attribute is an annotations attribute, add all annotations attached to it. */ public void addAnnotations(Attribute attr, Map<String, MetadataAnnotation> annotations) { Attribute toUse = attr; while (toUse != null) { if (toUse instanceof RuntimeVisibleAnnotations) { addAnnotationsHelper(annotations, (RuntimeVisibleAnnotations) toUse); } toUse = toUse.next; } } private void addAnnotationsHelper(Map<String, MetadataAnnotation> annotations, RuntimeVisibleAnnotations visibleAnnotations) { for (Iterator iterator = visibleAnnotations.annotations.iterator(); iterator.hasNext();) { Annotation visibleAnnotation = (Annotation) iterator.next(); // Only add annotations that we care about. if ((visibleAnnotation.type.indexOf("javax/persistence") != -1) || (visibleAnnotation.type.indexOf("org/eclipse/persistence") != -1)) { MetadataAnnotation annotation = buildAnnotation(visibleAnnotation); annotations.put(annotation.getName(), annotation); } } }
Taking an initial look to determine feasability of including patch from this bug.
Checked in fix as suggested. Tested with attached test case and JPA LRG. I was unable to write a regression test due to the unavailabliity of an ofuscator in the test framework. Reviewed: Tom Ware - reviewed user submitted fix
*** Bug 304602 has been marked as a duplicate of this bug. ***
The Eclipselink project has moved to Github: https://github.com/eclipse-ee4j/eclipselink