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...
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.
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...
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...
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).
----------------------
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?
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...
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;
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.
But.
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.
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.
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.
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).
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.
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.
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).