0

I am looking for transportation layer for gwt. I would like to create ajax request using generic method, f.e this is my DAO/service:

public class GenericDao<T extends GenericModel<T>> {
    private Logger logger = LoggerFactory.getLogger(this.getClass().getCanonicalName());
    @Transient protected Class<T> entityClass;


    public GenericDao() {
        super();
    }
    public GenericDao(Class<? extends GenericModel<T>> clazz) {
        this.entityClass = (Class<T>) clazz;
    }

    public T getBy(Long id) {
        return JPA.em().find(entityClass, id);
    }
    public List<GenericModel<T>> get() {
        logger.error("trying to get data from db");
        return getList();
    }
    public List<GenericModel<T>> getList() {
        return JPA.em().createQuery("FROM " + entityClass.getSimpleName()).getResultList();
    }
    public void save(GenericModel<T> entityClass) {
        JPA.em().getTransaction().begin();
        JPA.em().persist(entityClass);
        JPA.em().getTransaction().commit();     
    }
    public void update(T entityClass) {
        JPA.em().getTransaction().begin();
        JPA.em().merge(entityClass);
        JPA.em().getTransaction().commit();
    }

    public void delete(T entityClass) {
        JPA.em().getTransaction().begin();
        JPA.em().remove(entityClass);
        JPA.em().getTransaction().commit();
    }
}

GenericModel/Entity:

@MappedSuperclass
public  class GenericModel<T extends GenericModel<T>> implements Identifiable, Versionable {
    @Transient
    protected Class<T> entityClass;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Version
    private Integer version;

    // setter & getter
    @Override
    public Long getId() {return id;}
    public void setId(Long id) {this.id = id;}
    @Override
    public Integer getVersion() {return version;}
    public void setVersion(Integer version) {this.version = version;}

    // constructor
    public GenericModel() {
        Class<?> obtainedClass = getClass();
        Type genericSuperclass = null;
        for (;;) {
            genericSuperclass = obtainedClass.getGenericSuperclass();
            if (genericSuperclass instanceof ParameterizedType) {
                break;
            }
            obtainedClass = obtainedClass.getSuperclass();
        }
        ParameterizedType genericSuperclass_ = (ParameterizedType) genericSuperclass;
        try {
            entityClass = ((Class) ((Class) genericSuperclass_
                    .getActualTypeArguments()[0]));
        } catch (ClassCastException e) {
            entityClass = guessEntityClassFromTypeParametersClassTypedArgument();
        }
    }


    public GenericModel(Long id) {
        this();
        this.id = id;
    }
}

I am looking for mechanism that will allow me to use this generic service for all models on client side (each db entity have id- so I would like to downloads using ajax all my Entities this way, so I should have only one generic method for that on client side).

I've already checked:

  • GWT-RPC
  • RequestFactory
  • RestyGWT

But none of them support this feature.

I've found here:

https://www.mail-archive.com/google-web-toolkit@googlegroups.com/msg100095.html

information that: gwt-jackson supports generics and polymorphism. Unfortunately I didn't found any working example that. Can someone help, give an example, approved that information?

All entities have id and version parameter. So I would like to have one metod on client side RF that will allow me to get from server(service/dao/whatever) that entity by id- like this: Request getBy(Long id); But unfortunatelly I can't make it work. I like the RF way, so I've tried it first. Generally I don't wonna repeat code for downloading entity/proxy by id.

For better understanding, please look also on: RequestFactory client-side inheritance of typed class with generics

masterdany88
  • 5,041
  • 11
  • 58
  • 132

1 Answers1

0

I'm confused as to why you think RPC can't handle generics - according to your link, it can, but RestyGWT cannot. Granted, none of your JPA references make any sense in GWT, but those would live in a DAO on the server, not in the entity/model class themselves, or at least not in the client version. If you had a RPC method that returned T where <T extends GenericModel<T>>, then you would have serializers for every possible GenericModel<?> subtype, and any/all that are gwt-compatible could be sent over the wire.


Edit from update to question:

Your GenericModel class uses features of Java that cannot work in GWT, such as reflection. This cannot be compiled to GWT, since the compiler relies on removing reflection information to minimize your compiled size - leaving in general reflection information means leaving in details about all classes and members, even ones that it can't statically prove are in use, since some reflection might make use of them.

If there is a way to phrase your model object in a way that just deals with the data at hand, focus on that. Otherwise consider a DTO which is just the data to send over the wire - I'm not sure how you would plan to use the entityClass field on the client, or why that would be important to read from the superclass's generics instead of just using getClass().

RequestFactory will have a hard time dealing with generics - unlike RPC (and possibly RestyGWT) it cannot handle polymorphism the way you want, but will instead only send the fields for the declared type, not any arbitrary subtype. RPC will actually send the instance if it is something that the client can handle.

Colin Alworth
  • 17,801
  • 2
  • 26
  • 39
  • Gwt cannot convert T in interface to classess. He need implementation where T is suplied. So it have to be hardcoded. I am sure that RF cannot work with generics- I've tried to make it work. With RPC I didn't tried, but I did not found any working and good example. – masterdany88 Dec 01 '15 at 19:46
  • Please give me an example of client side code that will work with my generic DAO, or other generic server code. – masterdany88 Dec 01 '15 at 21:30
  • I don't understand the question - the DAO belongs on the server, since that is where your JPA etc is accessible. The client runs in the browser, which cannot have any access to your DB backend. Additionally, client code must be async, so we can't have blocking methods that wait for server work to finish. For example, generic RPC methods that use GenericModel should work, and those RPC calls can in turn talk to your DAO (modulo any authorization or other rules). Can you clarify your question to what *doesn't* work, rather than asking for a server class to make sense on a client? – Colin Alworth Dec 01 '15 at 22:17
  • RestyGWT works just fine with generics https://github.com/resty-gwt/resty-gwt/blob/master/restygwt/src/test/java/org/fusesource/restygwt/client/basic/ParameterizedTypeDTO.java . You have to annotate the parent classes with JsonSubTypes to make it aware of the inherited types. This works similar to the @ExtraTypes used by request factory. Different implementations but same type. – Chris Hinshaw Dec 01 '15 at 22:49
  • Sorry, I don't mean to suggest that it doesn't, just that the link in the question said it didn't at that time, while RPC did. – Colin Alworth Dec 02 '15 at 02:02
  • @ColinAlworth You say that it works with RPC? I haven't much test it more. Can You post an example with generics in client side dto? – masterdany88 Dec 02 '15 at 08:56
  • That's getting very close to 'recommend me a tool/library' or asking us to write code for you. GenericDao shouldn't be sent over the wire (see remarks on async and on jpa), but GenericModel, which you haven't shared yet, could. If it doesn't work, that points to a problem with GenericModel, or that you are using your DAO in a way that doesn't make sense. If you can clarify what you are asking for (besides "write code for me"), I'll be happy to give it a shot. – Colin Alworth Dec 02 '15 at 13:33
  • Ok. All `entities` have `id` and `version` parameter. So I would like to have one metod on client side RF that will allow me to get from server(service/dao/whatever) that `entity` by `id`- like this: `Request getBy(Long id);` But unfortunatelly I can't make it work. I like the RF way, so I've tried it first. Generally I don't wonna repeat code for downloading entity/proxy by id. I will post GenericModel class. – masterdany88 Dec 02 '15 at 13:55