GWT 2.4 Validation Tool not picking up @ExtraTypes on superclasses

298 views
Skip to first unread message

Brad Leupen

unread,
Sep 8, 2011, 12:08:08 PM9/8/11
to Google Web Toolkit
I have these interfaces:

@ExtraTypes({FooProxy.class})
public interface FooRequestFactory extends RequestFactory
{
...
}

@ExtraTypes({BarProxy.class})
public interface BarRequestFactory extends FooRequestFactory
{
...
}

if i look at the generated BarRequestFactoryDeobfuscatorBuilder.java,
there is no withClientToDomainMapping() entry for FooProxy. This
worked in the RC (albeit at runtime) but fails in the final release.

Why not simply add FooProxy.class to BarRequestFactory's @ExtraTypes
annotation? I can, but it is extremely cumbersome for me. Long story
short, I have an RF-based library that is broken out into various
modules. Clients of my library can pick and choose which modules to
include by creating a request factory interface which extends RF
interfaces of the dependent modules. This was cleanest way i could
find to compartmentalize all the @ExtraType's.

Brad

Thomas Broyer

unread,
Sep 8, 2011, 1:43:32 PM9/8/11
to google-we...@googlegroups.com
Can't you put your @ExtraTypes on the proxies instead? I.e. if you have "FooProxy extends SuperFooProxy", then why not put @ExtraTypes(FooProxy.class) on the SuperFooProxy interface?

Brad Leupen

unread,
Sep 8, 2011, 1:54:30 PM9/8/11
to Google Web Toolkit
Hey Thomas,

Thanks for the reply. I think I actually tried that at one point on
the RC and ran into a stack overflow. Regardless, the design still
wont really work for me because the base Component proxy object really
has no idea what it's subclasses are or its subclasses' dependent
ValueProxies.

Y2i

unread,
Sep 8, 2011, 5:25:08 PM9/8/11
to google-we...@googlegroups.com
I also have @ExtraTypes on RF due to stack overflow in RC.  Haven't tried yet in the release.

Y2i

unread,
Sep 8, 2011, 7:26:53 PM9/8/11
to google-we...@googlegroups.com
Brad, what if you place @ExtraTypes(FooProxy.class) on some RequestContext returned by methods of FooRequestFactory?

Kevin Jordan

unread,
Sep 8, 2011, 7:46:33 PM9/8/11
to Google Web Toolkit
Doesn't appear much has changed on the RequestFactoryGenerator in the
final release from RC1. I ended up having to do a copy of
RequestFactoryGenerator and change AllReachableTypesVisitor to be:
private static class AllReachableTypesVisitor extends
RequestMethodTypesVisitor {

private final RequestFactoryModel model;

List<HasExtraTypes> visitedTypes = new ArrayList<HasExtraTypes>();

public AllReachableTypesVisitor(RequestFactoryModel model) {
this.model = model;
}

@Override void examineTypeOnce(JClassType type) {
// Need this to handle List<Foo>, Map<Foo>
JParameterizedType parameterized = type.isParameterized();
if (parameterized != null) {
for (JClassType arg : parameterized.getTypeArgs()) {
this.maybeVisit(arg);
}
}
JClassType base = ModelUtils.ensureBaseType(type);
EntityProxyModel peer = this.model.getPeer(base);
if (peer == null) {
return;
}
peer.accept(this);
}

@Override public boolean visit(ContextMethod x) {
if (!this.visitedTypes.contains(x)) {
this.visitedTypes.add(x);
System.out.println("Visiting extra types for: " +
x.getQualifiedSourceName());
this.visitExtraTypes(x);
}
return true;
}

@Override public boolean visit(EntityProxyModel x) {
if (!this.visitedTypes.contains(x)) {
this.visitedTypes.add(x);
System.out.println("Visiting extra types for: " +
x.getQualifiedSourceName());
this.visitExtraTypes(x);
}
return true;
}

@Override public boolean visit(RequestFactoryModel x) {
if (!this.visitedTypes.contains(x)) {
this.visitedTypes.add(x);
System.out.println("Visiting extra types for: " +
x.getFactoryType().getQualifiedSourceName());
this.visitExtraTypes(x);
}
return true;
}

void visitExtraTypes(HasExtraTypes x) {
if (x.getExtraTypes() != null) {
for (EntityProxyModel extra : x.getExtraTypes()) {
System.out.println("Accepting type: " +
extra.getQualifiedSourceName());
extra.accept(this);
}
}
}
}

The problem seems to be that somehow a type will get itself as an
extraType and so it gets into an infinite loop where it visits itself
when it's mentioned in an @ExtraTypes from a superclass. To make it
not do that, I have it keep track of what ones it has already
visited. Annotating the superclass seems to be the only way to make
its subclasses available, but it also causes the infinite loop by
default. I have a few places in my code where I have proxies that
reference a superclass proxy that is for an abstract domain class and
will be assigned with a proxy subclass, but that failed until I added
them in @ExtraTypes to the superclass proxy. It seems that
polymorphism in RequestFactory at the moment automatically takes care
of making sure superclass proxies are available, but it doesn't take
care of subclasses that are assignable to a proxy.

Kevin Jordan

unread,
Sep 8, 2011, 7:50:33 PM9/8/11
to Google Web Toolkit
Also, after you put that in your copied RequestFactoryGenerator,
you'll need to put:
<generate-with
class="<package where you put your copied
generator>.RequestFactoryGenerator">
<when-type-assignable
class='com.google.web.bindery.requestfactory.shared.RequestFactory' /
>
</generate-with>
in your module's gwt.xml.

Kevin Jordan

unread,
Sep 8, 2011, 8:07:23 PM9/8/11
to Google Web Toolkit
Looking further, it would probably be best though if a fix for
RequestFactoryModel was checked in that had a check against the type
being examined and the type it gets for the proxy type in the
@ExtraTypes array:
private List<EntityProxyModel> checkExtraTypes(JClassType type,
boolean addModelExtraTypes)
throws UnableToCompleteException {
Set<EntityProxyModel> toReturn = new
LinkedHashSet<EntityProxyModel>();
if (addModelExtraTypes && extraTypes != null) {
toReturn.addAll(extraTypes);
}
for (JClassType toExamine : type.getFlattenedSupertypeHierarchy())
{
ExtraTypes proxyExtraTypes =
toExamine.getAnnotation(ExtraTypes.class);
if (proxyExtraTypes != null) {
for (Class<? extends BaseProxy> clazz :
proxyExtraTypes.value()) {
JClassType proxy =
oracle.findType(clazz.getCanonicalName());
if (proxy == null) {
poison("Unknown class %s in @%s",
clazz.getCanonicalName(), ExtraTypes.class
.getSimpleName());
} else /*check added here*/ if (!toExamine.equals(proxy) /
*and possibly !proxy.isAssignableTo(toExamine)*/) {
toReturn.add(getEntityProxyType(proxy));
}
}
}
}
if (toReturn.isEmpty()) {
return Collections.emptyList();
}
return new ArrayList<EntityProxyModel>(toReturn);
}

Unfortunately due to their use of private a lot in both, neither
RequestFactoryGenerator nor RequestFactoryModel are very
extendable...seems you have to end up making a copy of both for this
fix...

Brad Leupen

unread,
Sep 15, 2011, 9:49:57 AM9/15/11
to Google Web Toolkit
Thanks for all of the replies. I have had some time to dig into this a
little more. Long story short, the ValidationTool finds inherited
@ExtraTypes when run on its own from the command line but does not
when run as an automated annotation processor. I think it might have
something to do with the fact that my proxies are request factories
are organized into multiple projects, like so:

core-components-project:
com/acme/components/core/
Core.gwt.xml
client/
ComponentRequestFactory.java
ComponentServiceRequest.java
shared/
ComponentProxy.java
server/
Component.java
ComponentService.java

com/acme/components/foocomponents/
Foo.gwt.xml
client/
FooRequestFactory.java (extends
ComponentRequestFactory, has @ExtraType annotation declaring
FooComponentProxy.class)
shared/
FooComponentProxy.java (extends
ComponentProxy)
server/
FooComponent.java (extends Component)

com/acme/components/barcomponents/
Bar.gwt.xml
client/
BarRequestFactory.java (extends
ComponentRequestFactory, has @ExtraType annotation declaring
BarComponentProxy.class)
shared/
BarComponentProxy.java (extends
ComponentProxy)
server/
BarComponent.java (extends Component)


Product A-project: (includes core components project on eclipse build
path)
com/acme/producta/
ProductA.gwt.xml
client/
ProductARequestFactory.java (extends FooRequestFactory
and BarRequestFactory, @ExtraType for ProductAComponentProxy.class)
shared/
ProductAComponentProxy.java (extends ComponentProxy)
server/
ProductAComponent.java (extends Component)

I have methods in com.acme.components.core.ComponentService that
operate on Component objects and are expected to return the
appropriate polymorphic subclasses of ComponentProxy.

From the command line, the validation tool compiles a
ProductARequestFactoryObfuscatorBuilder with ComponentProxy,
FooComponentProxy, and BarComponentProxy, and ProductAComponentProxy.
When run as an annotation processor, I just get ProductAComponentProxy
and ComponentProxy.

Does this make any sense?

Brad Leupen

unread,
Sep 15, 2011, 9:55:21 AM9/15/11
to Google Web Toolkit
*"my proxies AND request factories are organized into multiple
projects" i meant to say

Bademus ᵗʰᵉ

unread,
Feb 22, 2013, 11:20:23 PM2/22/13
to google-we...@googlegroups.com
It seems that GenTool goes into infinite loop again

Version: gwt 2.5.1-rc1
Code:
public interface EntityBaseProxy extends EntityProxy { ... }

@ExtraTypes(AuthorProxy.class)
public interface UserProxy extends EntityBaseProxy { ... }

public interface AuthorProxy extends UserProxy { ... }


Result:
Exception in thread "main" java.lang.StackOverflowError
at java.util.Collections$UnmodifiableCollection.<init>(Collections.java:990)
at java.util.Collections$UnmodifiableList.<init>(Collections.java:1145)
at java.util.Collections$UnmodifiableRandomAccessList.<init>(Collections.java:1222)
at java.util.Collections.unmodifiableList(Collections.java:1131)
at com.google.web.bindery.requestfactory.gwt.rebind.model.EntityProxyModel.getExtraTypes(EntityProxyModel.java:110)
at com.google.web.bindery.requestfactory.gwt.rebind.RequestFactoryGenerator$AllReachableTypesVisitor.visitExtraTypes(RequestFactoryGenerator.java:123)
at com.google.web.bindery.requestfactory.gwt.rebind.RequestFactoryGenerator$AllReachableTypesVisitor.visit(RequestFactoryGenerator.java:95)
at com.google.web.bindery.requestfactory.gwt.rebind.model.EntityProxyModel.accept(EntityProxyModel.java:101)
at com.google.web.bindery.requestfactory.gwt.rebind.RequestFactoryGenerator$AllReachableTypesVisitor.visitExtraTypes(RequestFactoryGenerator.java:125)
at com.google.web.bindery.requestfactory.gwt.rebind.RequestFactoryGenerator$AllReachableTypesVisitor.visit(RequestFactoryGenerator.java:95)
...

Thomas Broyer

unread,
Feb 23, 2013, 6:33:55 AM2/23/13
to google-we...@googlegroups.com


On Saturday, February 23, 2013 5:20:23 AM UTC+1, Bademus ᵗʰᵉ wrote:
It seems that GenTool goes into infinite loop again

Version: gwt 2.5.1-rc1
Code:
public interface EntityBaseProxy extends EntityProxy { ... }

@ExtraTypes(AuthorProxy.class)
public interface UserProxy extends EntityBaseProxy { ... }

public interface AuthorProxy extends UserProxy { ... }

It's no news actually (and Brad was right, and I was wrong): https://code.google.com/p/google-web-toolkit/issues/detail?id=6912
Workaround: don't put @ExtraTypes on the super-interface of the "extra" interfaces (e.g. move @ExtraTypes to a RequestContext)

Jonathan Nash

unread,
Jun 13, 2013, 5:51:52 PM6/13/13
to google-we...@googlegroups.com
I have a related follow-up question.  I was getting a stack overflow at runtime because of the polymorphic hierarchy and was not using @ExtraTypes.  My hierarchy was 3 levels deep.  Top level is GenericType,  next level is CategoryType and EventType, and next level is four subtypes of CategoryType and 4 subtypes of EventType.

I finally got it working by putting @ExtryTypes in my request factory.  It only worked when I put the @ExtraTypes with the full list of 10 types above GenericType.  Initially I had tried to put @ExtraTypes with just 2 types above GenericType and @ExtraTypes with 4 types each above CategoryType and EventType.  This did not work.

Is this how it is intended to work?  

A related question. At one point I download all GenericTypes in the datastore (I use Objectify) and I want to see which of the lowest 8 types a particular entity is.  I am currently comparing the String of the class I am looking for with substring of the class name of the GenericType.  When I do getClass().getName() on the GenericType, returned from the datastore, I get something like:

com.packagename.shared.proxy.LevelThreeTypeProxyAutoBean_com_google_web_bindery_requestfactory_shared_impl_EntityProxyCategory_com_google_web_bindery_requestfactory_shared_impl_ValueProxyCategory_com_google_web_bindery_requestfactory_shared_impl_BaseProxyCategory$1

If I am trying to see if this is a 'com.packagename.shared.proxy.LevelThreeTypeProxy', i compare that string to the left substring with length of whatever the fully qualified name I'm looking for is.

Is there a better way to do this?

Thanks,

Jonathan
Reply all
Reply to author
Forward
0 new messages