Hi,
As a follow-up to Sahoo's message, Bill Shannon and I just had a
lengthy discussion about this issue, and the following is what
we concluded for behavior within Java EE environments.
As noted already, the spec clearly assumes that this case needs to
work when both runtime instances have access to the entity classes
and any required vendor persistence implementation classes.
It also is required to work for cases where the entities do not have
lazy properties/fields and/or relationships.
We can identify two ways to achieve this for the cases under
discussion where the entities have been designated with lazy
loadable state.
(1) no extra state -- the serialized state conforms to the
(unenhanced) entity class on the client.
(2) the enhanced class is available to the appclient container.
This could be achieved either by
(a) having the classes woven on the client side, or
(b) generating the woven classes on the server at deployment to
make them available to the client container.
Analyzing these in turn:
(1) As far as we can see, this doesn't provide all the needed support
for tracking of the lazy state, since in general the client could
be updating the detached instances and merging them back.
(2) (a)
To make this work, provider persistence implementation classes would
need to be available on the client, and sufficient information would
need to be made available to the provider so that the provider would
know which classes were in need of enhancement. We did *not*
however think it reasonable that the client define a persistent unit.
The knowledge of the classes in need of enhancement needs to be
computed on the server side anyway, and a means could/should be defined
for passing such information to the client container and/or provider.
(2) (b)
The enhanced classes could be generated on the server at deployment,
and packaged with the client jar.
-Linda
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