persistence@glassfish.java.net

Re: [Issue 1081] Remote business method of Session Bean returning JPA entity with lazy field

From: Sanjeeb Kumar Sahoo <Sanjeeb.Sahoo_at_Sun.COM>
Date: Wed, 06 Dec 2006 18:44:59 +0530

I see following issues with option #2:

1) It affects pluggability as there is no SPI defined to get the
enhanced byte codes.

2) It does not work when only a client module containing entity + ejb
interface classes + client classes is deployed. In such a case, the PU
is part of a separate EJB application that is deployed in the server.

3) It is not inter-operable with other vendors.

None of the above issues arise with option #1 which retains
Serialization compatibility at the cost of one case that does not work,
i.e. when a lazy field is set from a non-null value to null value by the
client and entity is sent back to the server for merging.

How about having a union of #1 & #2, where there are two enhancement
strategies, viz:
a) add no extra state (like #1),
b) add extra state (like #2).
Make #a the default strategy and #b an optional strategy. If #b is
supported, then leave it to implementation to decide how enhanced
classes can be made available to client container. It could be achieved
by mechanisms suggested in option #2 or via static enhancement or
something else. Any application that wishes to use #b is non-portable.

Thanks,
Sahoo

Linda DeMichiel wrote:
> 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