Hello Sahoo,
I agree that this is a valuable usecase but is limited by the
current wording of the specification. Perhaps Mike or Linda can voice
the intentions of the spec here but I do not believe the serialization
specifics were intended to apply only to when the serialized objects
would be used for merging. Without a mechanism for the user to tell
the Persistence Provider about the target environment the Persistence
Provider has to assume that the entities are being serialized to the
vendor's environment in order to be compliant with the sections of the
specification mentioned below. Including API for the user to use to
notify the Persistence Provider of the target environment is a viable
option that has been mentioned before but would be outside other
specification an in order to proceed on this issue this is the approach
we should take.
--Gordon
Sanjeeb Kumar Sahoo wrote:
Hi,
This is a fairly important issue and please excuse me for the rather
long email. Since we could not reach at a conclusion on this issue
during our phone conversation, we agreed to start an email discussion.
For the benefits of those who were not part of our phone discussion,
here is a brief back ground:
Use case:
------------
There is a remote business interface called Facade
which returns a JPA entity type object City in a business
method. The remote interface and the entity class definition is shown
here:
@Remote
public interface Facade {
City getCityById(int cityId);
}
@Entity
public class City implements Serializable {
private int id;
private Region region;
@Id @GeneratedValue(strategy = GenerationType.AUTO)
public int getId() {...}
public void setId(int id) {...}
@ManyToOne(fetch = FetchType.LAZY)
public Region getRegion() {...}
public void setRegion(Region region) {...}
...
}
The ear file is packaged like this:
ear
lib/common.jar (contains City.class, Region.class, Facade.class.)
ejb.jar (contains FacadeBean.class and persistence.xml)
appclient.jar (contains Client.class)
As you can see from the above packaging structure, the persistence unit
(PU) is scoped to the ejb module and client is using the entity classes
as POJOs. For the client, they represent data transfer objects (DTOs)
while accessing the session bean's remote business interface.
The bug: (https://glassfish.dev.java.net/issues/show_bug.cgi?id=1081)
-----------
When client calls the business method of the bean, it gets an exception
during unmarshaling. The exception message reads something like this:
Caused by: java.io.IOException: Mismatched serialization UIDs : Source
Root cause:
---------------
The above exception is caused by the fact that TopLink Essential, in
order to support lazy loading, has enhanced the classes in the EJB
container in a such way that the client can't deserialize them using
the original class even though the appclient container has TopLink
Essential classes in it's classpath.
I do feel that it is a supported portable use case, but there were two
other kinds of opinions, viz:
1) It is a supported use case, but appclient container should somehow
enhance the class so that it can be deserialized.
2) It is not a supported use case, client must define persistence unit
so that class can be enhanced.
As you can see, there is a subtle difference between #1 & #2. Even
though #1 makes it transparent, it requires the client to have access
to the same persistence provider runtime as the server. Is this a
reasonable expectation? Shouldn't a JBoss appclient be allowed to
call an EJB deployed in GlassFish without having to require GlassFish
classes in JBoss client container?
#2 requires client to have access to persistence.xml. If I
remember
correctly, the primary reason to require persistence.xml was that
container can assume JPA annotated entity classes being used as client
view
classes in a Java EE environment in the absence of persistence.xml.
Here is what I find in the spec:
1. section #2.1:
If an entity instance is to be passed by value as a detached object
(e.g., through a remote interface), the entity class must implement the
Serializable interface.
2. section #3.2.4.2 (Detached Entities and Lazy Loading):
Serializing entities and merging those entities back into a persistence
context may not be interoperable across vendors when lazy properties or
fields and/or relationships are used.
A vendor is required to support the serialization and subsequent
deserialization and merging of detached entity instances (which may
contain lazy properties or fields and/or relationships that have not
been fetched) back into a separate JVM instance of that vendor's
runtime, where both runtime instances have access to the entity classes
and any required vendor persistence implementation classes.
When interoperability across vendors is required, the application must
not use lazy loading.
Please note that the above section clearly talks about merging
the
detached object in a separate JVM, which is not attempted by
the client in
our example. It just calls the session bean to get the entity and it
has no intention to access the lazy fields.
IMHO, requiring that JPA classes that do not have lazy
attributes can only be portably used in remote interface will
be a serious limitation. It throws away the big promise that
JPA entity classes can be used as DTOs because in reality many entities
have lazy attributes. I always thought the spec even allowed the client
to access the lazy fields
as long as it is populated by the server. It is a contract between the
server and client developer. If the lazy fields have not been populated
by the server, client can't access them.
Thanks,
Sahoo