问题
I am trying to write a generic class to avoid code repetition. I would like to have generic methods for:
- Get Entity/Model from server by id.
- Get List of all Entities/Models from server.
- Send to server and save in db Entity/Model.
It should work with Generic classes, e.g.:
Services<PizzaProxy> factory = GWT.create(Services.class);
factory.initialize(new SimpleEventBus());
GenericContext<PizzaProxy> context = factory.genericContext();
context.get().to(new Receiver<List<GenericProxy<PizzaProxy>>>() {
@Override
public void onSuccess(List<GenericProxy<PizzaProxy>> response) {
for(GenericProxy<PizzaProxy> p: response) {
logger.severe(p.getId()) + " " + p.getVersion());
}
}
}).fire();
I have working server side. Now I struggle with client side code.
The goal is to write:
GenericModel
,GenericDao
,GenericLocator
,GenericService
,GenericProxy
,GenericContext
.
Here is my server side code, which works (doesn't report any compile or run-time errors, as I suppose):
SERVER
GenericModel
@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();
}
}
}
GenericDao
public class GenericDao<T extends GenericModel<T>> {
@Transient protected Class<T> entityClass;
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<T> get() {
return getList();
}
public List<T> getList() {
return (List<T>) JPA.em().createQuery("FROM " + entityClass.getSimpleName()).getResultList();
}
public void save(T entityClass) {
JPA.em().persist(entityClass);
}
public T saveAndReturn(T entityClass) {
this.save(entityClass);
return entityClass;
}
public void saveOrUpdate(T entityClass) {
// TODO
}
public void update(T genericDao) {
JPA.em().merge(genericDao);
}
public void delete(T genericDao) {
JPA.em().remove(genericDao);
}
@PrePersist
protected void prePersist() {
preUpdate();
}
@PreUpdate
protected void preUpdate() {
// TODO Update Version
}
}
GenericLocator
public class GenericLocator<GL extends GenericLocator<GL, GD, GM, id>, GD extends GenericDao<GM>, GM extends GenericModel<GM>, id> extends Locator<GenericModel<GM>, Long> {
@Override
public GenericModel<GM> create(Class<? extends GenericModel<GM>> clazz) {
try {
return clazz.newInstance();
} catch (InstantiationException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
@Override
public GenericModel<GM> find(Class<? extends GenericModel<GM>> clazz, Long id) {
GenericDao<GM> dao = new GenericDao<GM>(clazz);
return dao.getBy(id);
}
@Override
public Class<GenericModel<GM>> getDomainType() {
GenericModel<GM> model = new GenericModel<GM>();
return (Class<GenericModel<GM>>) model.getClass();
}
@Override
public Long getId(GenericModel<GM> model) {
return model.getId();
}
@Override
public Integer getVersion(GenericModel<GM> model) {
return model.getVersion();
}
@Override
public Class<Long> getIdType() {
return Long.class;
}
}
CLIENT/SHARED
GenericProxy
@ProxyFor(value = GenericModel.class, locator = GenericLocator.class)
public interface GenericProxy<T extends GenericProxy<T>> extends EntityProxy {
public Long getId();
public Integer getVersion();
}
GenericContext
@Service(value = GenericDao.class, locator = MyServiceLocator.class)
public interface GenericContext<T extends GenericProxy<T>> extends RequestContext {
Request<T> getBy(Long id);
Request<List<T>> get();
Request<Void> save(T entity);
}
Here is the compilation error that occurs:
[INFO] Adding '2' new generated units
[INFO] See snapshot: /tmp/pl.derp.shared.rf.GenericContextImpl5428453302732754803.java
[INFO] Ignored 1 unit with compilation errors in first pass.
[INFO] Compile with -strict or with -logLevel set to TRACE or DEBUG to see all errors.
[INFO] Tracing compile failure path for type 'pl.derp.shared.rf.GenericContextImpl'
[INFO] [ERROR] Errors in '/home/korbeldaniel/git/derp3/tutorial/target/.generated/pl/derp/shared/rf/GenericContextImpl.java'
[INFO] [ERROR] Line 22: T cannot be resolved to a type
[INFO] [ERROR] Line 29: T cannot be resolved to a type
[INFO] [ERROR] Line 18: The interface Request cannot be implemented more than once with different arguments: Request<List<T>> and Request<List<T>>
[INFO] [ERROR] Line 22: T cannot be resolved to a variable
[INFO] [ERROR] Line 22: Syntax error on token "extends", instanceof expected
[INFO] [ERROR] Line 30: The interface Request cannot be implemented more than once with different arguments: Request<T> and Request<T>
[INFO] [ERROR] Line 41: T cannot be resolved to a type
[INFO] [ERROR] Line 17: T cannot be resolved to a type
[INFO] [ERROR] Line 30: T cannot be resolved to a type
[INFO] [ERROR] Line 22: Syntax error on token "class", invalid Name
[INFO] [ERROR] Line 20: The method with(String...) from the type AbstractRequest<BaseProxy,List<T>> refers to the missing type T
[INFO] [ERROR] Line 3: The type GenericContextImpl must implement the inherited abstract method GenericContext.save(GenericProxy)
[INFO] [ERROR] Line 32: The method with(String...) from the type AbstractRequest<BaseProxy,T> refers to the missing type T
[INFO] [ERROR] Line 18: T cannot be resolved to a type
[INFO] [ERROR] Hint: Check that the type name 'pl.derp.shared.rf.GenericContextImpl' is really what you meant
[INFO] [ERROR] Hint: Check that your classpath includes all required source roots
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
As you can see errors point to generated class implementation of mine request factory interfaces. I don't know how to deal with it.
来源:https://stackoverflow.com/questions/33941560/gwt-request-factory-generics-and-inheritance-on-client-side