[ 
https://issues.apache.org/jira/browse/OPENJPA-386?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=12746273#action_12746273
 ] 

Jody Grassel commented on OPENJPA-386:
--------------------------------------

The problem was how ClassMetaData.hasConcretePCSuperclass() handled mapped 
superclasses.  Let's say we have the following classes:

@MappedSuperclass
public class MSC

@Entity
@IdClass(MyIdClass.class)
public class EntityA extends MSC

(Note that the @MappedSuperclass type "MSC" is not abstract, which is perfectly 
legal with the JPA Spec.)

Now, when an entity extending the MSC is annotated with @IdClass, the metadata 
processing notes that there are PC-enhanced superclasses, and needs to analyze 
them to check if they declare any identity elements, in order to ensure that 
the @IdClass specified will address them.  It uses this method in ClassMetaData 
to check if it has a PC superclass that is concrete (effectively, any entity 
class types that are further up the inheritance tree.:

    /**
     * Return true if this class has a concrete persistent superclass.
     */
    private boolean hasConcretePCSuperclass() {
        if (_super == null)
            return false;
        if (!Modifier.isAbstract(_super.getModifiers())))
            return true;
        return getPCSuperclassMetaData().hasConcretePCSuperclass();
    }

The line: if (!Modifier.isAbstract(_super.getModifiers()))) is responsible for 
detecting @MappedSuperclasses, however it relies exclusively on the class being 
abstract, something that, while recommended, is not required by the JPA Spec.  
So it will incorrectly treat a @MappedSuperclass as a regular entity, resulting 
in this Exception:

org.apache.openjpa.util.MetaDataException: Field "testcase.EntityA.id" cannot 
be a primary key.  Primary key fields can only be declared in base persistent 
classes that also declare their identity type- to be "application".
     at 
org.apache.openjpa.meta.ClassMetaData.validateNoPKFields(ClassMetaData.java:2025)
     at 
org.apache.openjpa.meta.ClassMetaData.validateAppIdClass(ClassMetaData.java:1905)
     at 
org.apache.openjpa.meta.ClassMetaData.validateIdentity(ClassMetaData.java:1851)
     at 
org.apache.openjpa.meta.ClassMetaData.validateMeta(ClassMetaData.java:1768)
     at org.apache.openjpa.meta.ClassMetaData.resolve(ClassMetaData.java:1641)
...

The solution was to simply add another check for the @MappedSuperclass.  This 
is already done with the ClassMetaData.isAbstract() method in trunk (which is 
set true if a class type explicitly is annotated with @MappedSuperclass, or is 
defined as a mapped-superclass by ORM XML), which was brought down to 1.2.x and 
1.3.x in OPENJPA-1061.  With the following change:

private boolean hasConcretePCSuperclass() {
        if (_super == null)
            return false;
        if (!Modifier.isAbstract(_super.getModifiers()) && 
                        (!getPCSuperclassMetaData().isAbstract()))
            return true;
        return getPCSuperclassMetaData().hasConcretePCSuperclass();
    }

With the above change, a @MappedSuperclass can now be identified whether or not 
its class type is actually a Java abstract class or not.

> org.apache.openjpa.meta.ClassMetaData.validateAppIdClass() does not take 
> @MappedSuperclass into account
> -------------------------------------------------------------------------------------------------------
>
>                 Key: OPENJPA-386
>                 URL: https://issues.apache.org/jira/browse/OPENJPA-386
>             Project: OpenJPA
>          Issue Type: Bug
>          Components: kernel
>    Affects Versions: 0.9.7, 1.0.0, 1.0.2
>         Environment: BEA WebLogic 10.0 under Windows XP SP1
>            Reporter: Matthew L. Schwickerath
>            Assignee: Jody Grassel
>
> We have a @MappedSuperclass that is the base for all of our entity bean 
> classes.  This class contains the @Version (and @Column for the version 
> field) that all of our entity beans use.  But, in 
> ClassMetaData.validateAppIdClass(), if an entity bean class has a superclass, 
> and the entity bean has an @IdClass, it expects that superclass to have an 
> @IdClass also.  All of our entity beans have an @IdClass (even if they only 
> have a single part key), but our @MappedSuperclass does not have an @IdClass. 
>  This scenario works under JBoss 4.2.0 and Sun AS 9, but produces a 
> NullPointerException in OpenJPA at:
>         if (_super != null) {
>             // concrete superclass oids must match or be parent of ours
>             ClassMetaData sup = getPCSuperclassMetaData();
>             if (!sup.getObjectIdType().isAssignableFrom(_objectId))  // <--- 
> NullPointerException here

-- 
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.

Reply via email to