Prevent class conversion when compiling modules

46 views
Skip to first unread message

Warpitaly

unread,
Jan 13, 2010, 10:21:00 AM1/13/10
to Google Web Toolkit
Greetings, we're developing a large JEE6 application that relies on
JPA/TopLink2 to serialize its entities.
A subset of such entities is required in the GWT front-end.
e.g., let's name:

entities.A -> one of the entities:
@Entity
public class A implements Serializable{
[...]
int num;
}

entities.B -> another one, containing an object A:
@Entity
public class B implements Serializable{
[...]
int age;
A a;
}

entities.A is strictly internal to the JEE6 application, while
entities.B is used in the GWT front-end; i.e., the GWT front-end NEVER
uses B.a, but it's a field required inside the JEE6 application.
If we add to the GWT modules just B, A is included as well. Is there a
way to prevent such behavior? Is there some sort of "transient"
annotation we can use?

Obviously the issue arises in several classes, and creating duplicates
or interfaces would not be feasible.

Any help will be appreciated...

Chris Lercher

unread,
Jan 13, 2010, 12:45:32 PM1/13/10
to Google Web Toolkit
For Hibernate there's Gilead, which provides an @ServerOnly annotation
( http://code.google.com/webtoolkit/articles/using_gwt_with_hibernate.html
). Maybe there exists a similar solution for TopLink?

Also, have you actually tried the transient keyword? The DevGuide
( http://code.google.com/webtoolkit/doc/latest/DevGuideServerCommunication.html#DevGuideSerializableTypes
) says:

"The transient keyword is honored, so values in transient fields are
not exchanged during RPCs."

This could indicate to gwtc, that it doesn't need to include the
class, as long as it doesn't get instantiated anywhere in your client
code.

Warpitaly

unread,
Jan 14, 2010, 3:30:32 AM1/14/10
to Google Web Toolkit
Thanks for the reply.
We already used both Gilead and Dozer, but unfortunately Hibernate is
not Toplink: we need JPA2.

As regards the transient keyword, as per JPA specs it would apply to
the entity at whole (i.e., the field would not be persisted neither by
JPA).
"You can, however, override a field or property's default persistence
by marking it with the @Transient annotation or the Java keyword
transient."
(taken from http://java.sun.com/developer/technicalArticles/J2EE/jpa/
)

Hence, I'm not sure that the problem is solved...

On 13 Gen, 18:45, Chris Lercher <cl_for_mail...@gmx.net> wrote:
> For Hibernate there's Gilead, which provides an @ServerOnly annotation

> (http://code.google.com/webtoolkit/articles/using_gwt_with_hibernate.html


> ). Maybe there exists a similar solution for TopLink?
>
> Also, have you actually tried the transient keyword? The DevGuide

> (http://code.google.com/webtoolkit/doc/latest/DevGuideServerCommunicat...

Chris Lercher

unread,
Jan 14, 2010, 4:53:27 AM1/14/10
to Google Web Toolkit
Just an idea - i haven't tried it: Can you mark your field transient,
but have getters/setters with JPA annotations which read/modify the
field?

Warpitaly

unread,
Jan 14, 2010, 8:00:59 AM1/14/10
to Google Web Toolkit
I don't think so: the GWT compiler would find a method whose signature
contains class A, hence including it again.

I'm afraid the only way is to create a Bb class, that is identical to
B except it doesn't contain any reference to A.
But you will ALL agree that this is quite a lame solution...

Chris Lercher

unread,
Jan 14, 2010, 8:12:51 AM1/14/10
to Google Web Toolkit
On Jan 14, 2:00 pm, Warpitaly <giorgio.dava...@gmail.com> wrote:
> I don't think so: the GWT compiler would find a method whose signature
> contains class A, hence including it again.

I'm not so sure about that. If your client never uses the getter/
setter, it can (theoretically) be pruned. The reason such pruning
cannot be done with a non-transient field is that this would incur
data loss (when sending the object back to the server).

Warpitaly

unread,
Jan 14, 2010, 8:22:53 AM1/14/10
to Google Web Toolkit
We tried that and it works as said in my previous post: the presence
of class A in the method signature is enough to make it required.
Actually, the same applies to mere transient fields: even if the field
is transient and doesn't have a getter/setter, the class is still
required...
Quite disappointing honestly!

Chris Lercher

unread,
Jan 14, 2010, 8:55:30 AM1/14/10
to Google Web Toolkit
Well, it works for me. I didn't try it with TopLink - I used POJOs
instead - but when I declare the field transient, it works (according
to the SOYC Compile Report).

----------------------
Example:

public class WantThat implements Serializable {
private transient DontWantThat dontWantThat;

public DontWantThat getDontWantThat() {
return dontWantThat;
}
}

public class DontWantThat implements Serializable {

}

@RemoteServiceRelativePath("some")
public interface SomeService extends RemoteService {
WantThat getWantThat();
}
-------------------------

DontWantThat is not in my Compile Report. If I remove the transient
keyword, it is.

Maybe there's something different with your case. Maybe something is
accessing your "getDontWantThat()"? Circular references at least?

Warpitaly

unread,
Jan 15, 2010, 5:25:12 AM1/15/10
to Google Web Toolkit
On 14 Gen, 14:55, Chris Lercher <cl_for_mail...@gmx.net> wrote:
> DontWantThat is not in my Compile Report. If I remove the transient
> keyword, it is.
>
> Maybe there's something different with your case. Maybe something is
> accessing your "getDontWantThat()"? Circular references at least?

As far as I understand, when you do something like what you proposed
GWT first compiles all the classes, then prunes the one that are not
required.

Hence, if your class DontWantThat is a transient member of WantThat it
it will be compiled and later on pruned.
Try adding a .clone() to DontWantThat and you'll see the compiler
exploding...

getaceres

unread,
Jan 21, 2010, 11:12:27 AM1/21/10
to Google Web Toolkit
I have something similar. I have this:

package com.company.pack
class A {}

package com.company.client
class B implements Serializable {
<some serializable fields>
private transient A field;

private A getA() {
return field;
}

private void setA(A val) {
this.field = val;
}
}

Both classes are JPA classes and it's only that B class has a
relationship with a non serializable A class, which the GWT client
doesn't have to know about. The rest of it, is serializable.
In this case, class A and B are in the same jar and the jar has the
sources included, but only B is in the GWT module (the client folder).
When I try to include this jar in my GWT project, I get an exception:

No source code is available for type com.company.pack.A; did you
forget to inherit a required module?

I tried putting the GwtTransient annotation to field A but the result
is the same. I think that GWT should completely ignore the classes
that are transient and its getters and setters and don't try to even
compile them.
It's a shame that, almost for every hibernate class that I have, I
have to create another class which has exactly the same fields, except
for one or two of them, and that I have to be putting all the data
from one bean to another all the time. It would be so much simple to
mark in my beans just the parts that the compiler shouldn't care
about.

On 14 ene, 14:55, Chris Lercher <cl_for_mail...@gmx.net> wrote:
> Well, it works for me. I didn't try it with TopLink - I used POJOs

> instead - but when I declare the fieldtransient, it works (according


> to the SOYC Compile Report).
>
> ----------------------
> Example:
>
> public class WantThat implements Serializable {

>         privatetransientDontWantThat dontWantThat;

Chris Lercher

unread,
Jan 21, 2010, 12:24:04 PM1/21/10
to Google Web Toolkit
I believe that what you expect from the GWT compiler is probably a lot
harder to achieve than "just" pruning unused methods (which is already
a great feature IMO).

gwtc compiles Java source -> Javascript. I assume that it can't read
Java bytecode at all (?) So just providing a jar file which contains
class A as bytecode won't work.

In theory, gwtc might be able to completely ignore A, but that's
generally not so easy. (It's something that javac can't do either: It
needs a .java file or a .class file for every type you reference.)

Therefore, I wouldn't say that it's a shame, or that it's
disappointing at all. It would be a quite ambitious feature for a
compiler of a strongly typed language.

Warpitaly

unread,
Jan 21, 2010, 12:32:13 PM1/21/10
to Google Web Toolkit
I would agree with you, if not for the small fact that GWT does not
recognize some elementary J2SE features (clone, sublist, etc).
I understand the reasons behind that, and accept them.

But.

I there-say that ignoring fields marked as @transient should be quite
easy to implement...

Chris Lercher

unread,
Jan 21, 2010, 12:54:34 PM1/21/10
to Google Web Toolkit
On Jan 21, 6:32 pm, Warpitaly <giorgio.dava...@gmail.com> wrote:
> I there-say that ignoring fields marked as @transient should be quite
> easy to implement...

If none of the gwt compiled code will access the field, it's certainly
easy. But that's unlikely (you have getters and setters, right?).

If some of your client code does access the field - and this can
happen indirectly - the class signature will be required. But how do
you know that at compile time, if you can't compile the methods that
access the fields (because they would need the class signature,
too)... Chicken and egg problem. Probably it can be solved, but 'easy
to implement' might be an understatement.

getaceres

unread,
Jan 22, 2010, 2:42:43 AM1/22/10
to Google Web Toolkit
The problem is that the source code of both classes is in the jar.

My jar has something like this:

com.company
|- Module.gwt.xml
|- pack
|- A.class
|- A.java
|- client
|- B.class
|- B.java

So both source files are available but only B file is part of the
module, since it's the only class that's in the client package.

getaceres

unread,
Jan 22, 2010, 2:48:35 AM1/22/10
to Google Web Toolkit
In my case, getter and setters will only be used in the server. Not
even in the RPC server implementation, but in a called EJB so, as long
as you don't use the getter or setter in the code, they can be
ignored. If you use them, failing the compilation would be enough.

Let's say that you have Class A with a transient method A.field marked
as transient in java or with the GwtTransient annotation:

- Mark field A.field and every method in A that uses field as
unavailable.
- If you find in the client code a class that uses A.field or any of
the methods of A marked as unavailable, fail the compilation and
inform the user about "Line X,Y: Use of transient method A.method".
- Now the user either, removes the calling method from its code or
removes the transient keyword from the field.

In my case, that wold be enough since I will not ever call any of this
getter or setters in the GWT code.

Chris Lercher

unread,
Jan 22, 2010, 4:43:22 AM1/22/10
to Google Web Toolkit
Compilers usually need full type information before they can tell, who
calls who. So this will probably add an additional compile step (or
maybe change the compiler architecture?) Still, I think your suggested
soultion uses a good approach, and you should create an entry in the
issue tracker for this.

Thinking about it, however, I personally wouldn't include this
functionality directly in the compiler: Even if it succeeds and
doesn't slow the compiler too much down, it means that the compiler
will accept classes that are partially invalid (class B could call
anything on class A, the compiler won't be able to check this, if it
decides to ignore A). This would create rather strange semantics for
"my class compiles successfully" - it depends on the question, if some
methods will be used or not.

However, I see two possible alternative solutions:

(A) Provide a pre-compiler that removes specially annotated fields. It
will be necessary to annotate the methods that access the fields
(directly or indirectly), too. Then allow GWTRPC serialization to
interact between the two versions of the class.

or (B) In addition to <source path="..."/> in the module xml, there
could be an element <source-dependency path="..."/>, which would mean:
Don't attempt to compile the java files in that path, but only read
their signature (basically treat the classes similar to interfaces).
This way, the type information can be provided to the compiler, and it
can work as usual. It would require however, that the java file is
available to you - you can't use this, if you only have the .class
files.
[In your case, getaceres, you'd add the package 'pack' to the source-
dependency path.]

I'm a lot more for (A), because it keeps semantics clean. Keep in mind
that in reality, you're trying to use different versions of the class
on the server and client. All you want is, that you don't have to
write and maintain the two similar versions (which is a legitimate
reason).

getaceres

unread,
Feb 4, 2010, 8:42:08 AM2/4/10
to Google Web Toolkit
I chose the wrong letter to describe my algorithm. Going to my
example:

Class A not serializable.
Class B serializable but with a B.field of type A marked as transient.

In this case, only B has to be taken into account, which is the only
class that uses A. The compiler would ignore completely A and mark
B.field and all the methods in B which use B.field as invalid (not
translatable). If any class C uses a method in B which has been marked
as invalid, then the compilation fails. In this case, there isn't any
possible mistake. The only way to use B.field or any invalid method in
B and not declaring it in the code would be to use reflection, which
is not supported by GWT so if the code compiles, it will work for
sure. At least, no one will ever call any method which uses directly
or indirectly something related to A because in that case, the
compilation would have failed.

I don't know much about modern compilers (apart from flex and yacc)
and much less about the GWT compiler, but I don't think that
implementing this would be very complex. On the code analysis of B
(lexical or semantical) you put some information in a Hash Table which
is consulted every time another class uses B.something. Of course,
this will slow the compilation process, specially if B is a overused
class which has a lot of functionality, but at least for me, it would
be worth the extra compilation time just to be able to reduce my
duplicated code.

dolc...@gmail.com

unread,
Feb 4, 2010, 9:19:48 AM2/4/10
to Google Web Toolkit
Well as a work around to see if/where gwtc is needing class A you
could create a "dummy" class using the super directive in your module
gwt that is serializable (and empty).

Chris Lercher

unread,
Feb 4, 2010, 9:44:01 AM2/4/10
to Google Web Toolkit
GWT doesn't allow reflection, but it does allow polymorphism. Let's
assume your client uses interface IC which is implemented by C1 and
C2. Now C1.x() is marked as invalid, but C2.x() isn't. Now your client
also can't use IC.x() anymore. It better not be toString()...

This is just one example for the strange semantics this would create.
I don't say that it's necessarily bad, but it's so different from the
semantics we're used to expect from a compiler. For me, one of the
most important things about a compiler is reliability. This doesn't
only mean that it should ideally be free from bugs. It means, that it
must be easy to determine which things will compile, and which won't.
Otherwise, we'll end up with something that's even worse than a C++
compiler: Slow, and little tooling support compared to Java (it's
incredibly hard to write good tools for C++, because the semantics are
too complex even for really good tool developers.)

Still I somehow like your idea. It just shouldn't be part of the
compiler. If it happens in a pre-compilation step that can be done
independently of the compiler, everything is fine, because then we can
keep our compiler simple and reliable.

getaceres

unread,
Feb 4, 2010, 1:06:48 PM2/4/10
to Google Web Toolkit
You are right, I didn't realize about the polymorphism problem since
you can always get an Object or interface as parameter and then
execute any of its methods, so you don't know what class you might
get. I guess a simplification of the problem would be to mark as
invalid only the field and its getter and setter so, any other method
which use the field or the getter or setter, even in class B, must
fail the compilation and also fail if either the fields or its
accessors override any method.

Chris Lercher

unread,
Feb 5, 2010, 6:41:32 AM2/5/10
to Google Web Toolkit
Does anybody know a source code transformation tool that makes it easy
to simply remove methods that are annotated with a certain annotation
from source code?

I know how to do this with ANTLR, but it should really be a lot
easier.
There's the "Annotation Processing Tool (apt)"
http://java.sun.com/javase/6/docs/technotes/guides/apt/GettingStarted.html
- but I don't think it's tailored to only removing some methods, while
leaving everything else intact (ideally even whitespace and comments).

If we had such a tool, the rest of our problem could probably be
solved relatively easily (allow serialization to occur between both
versions of the class).

Reply all
Reply to author
Forward
0 new messages