RequestFactory 客户端继承类型化 class 与泛型
RequestFactory client-side inheritance of typed class with generics
我想知道,是否可以将请求工厂 proxy/context 的通用 类 用于所有实体的通用操作,例如 getById(Long id)
.
在我的应用程序中,我会有很多像 类 这样的词典,它们只有 id
和 name
参数,所以我想编写一次功能并通过继承使用它在休息 类:
服务器实现如下:
领域模型类
@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;
}
}
@MappedSuperclass
public abstract class GenericDictionaryModel<T extends GenericModel<T>> extends GenericModel<T> {
private String name;
@Transient
private String optionDisplayName;
// private boolean active = true;
public String getName() {return name;}
public void setName(String name) {this.name = name;}
// public boolean getActive() {return active;}
// public void setActive(boolean stat) {this.active = stat;}
public String getOptionDisplayName() {return optionDisplayName;}
public void setOptionDisplayName(String optionDisplayName) {this.optionDisplayName = optionDisplayName;}
public GenericDictionaryModel() {
super();
}
public GenericDictionaryModel(Long id, String name) {
super(id);
this.name = name;
}
}
@Entity
public class PageI extends GenericDictionaryModel<PageI> {
@ManyToMany(cascade = CascadeType.ALL)
private List<Content> contents;
/* Getters and Setters */
public List<Content> getContents() {
return contents;
}
public void setContents(List<Content> contents) {
this.contents = contents;
}
}
DAO 类
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<T> get() {
// }
public List<GenericModel<T>> getList() {
List<T> resultList = JPA.em().createQuery("FROM " + entityClass.getSimpleName()).getResultList();
logger.error(resultList.toString());
return JPA.em().createQuery("FROM " + entityClass.getSimpleName()).getResultList();
}
}
public class GenericDictionaryDao<T extends GenericDictionaryModel<T>> extends GenericDao<T>{
private Logger logger = LoggerFactory.getLogger(this.getClass().getCanonicalName());
// public T getBy(Long id) {
// return super.getBy(id);
// }
public List<GenericModel<T>> getByName() {
return super.get();
}
// public List<T> getListOrderedByName() {
// public List<GenericDictionaryModel> getListOrderedByName() {
public List<GenericDictionaryModel> getListOrderedByName2() {
return null;
}
public List<GenericDictionaryModel<T>> getListOrderedByName() {
try {
return JPA.em()
.createQuery("FROM " + entityClass.getSimpleName() + " ORDER BY name")
.getResultList();
} catch (ClassCastException e) {
return new LinkedList<GenericDictionaryModel<T>>();
}
// return null;
}
}
这是共享的实现:
代理:
@ProxyFor(value = GenericModel.class, locator = GenericLocator.class)
public interface GenericProxy extends EntityProxy {
public Long getId();
public void setId(Long id);
public Integer getVersion();
public void setVersion(Integer version);
}
@ProxyFor(value = GenericDictionaryModel.class, locator = GenericLocator.class)
public interface GenericDictionaryProxy extends GenericProxy {
public String getName();
public void setName(String name);
}
@ProxyFor(value = PageI.class, locator = GenericLocator.class)
public interface PageIProxy extends GenericDictionaryProxy {
public List<ContentIProxy> getContents();
public void setContents(List<ContentIProxy> contents);
public static final String Contents = "contents";
}
和上下文/服务:
@Service(value = GenericDao.class, locator = MyServiceLocator.class)
@ExtraTypes( {
GenericProxy.class
} )
public interface GenericContext extends RequestContext {
Request<GenericProxy> getBy(Long id);
Request<List<GenericProxy>> get();
Request<Void> save(GenericProxy entity);
}
@Service(value = GenericDictionaryDao.class, locator = MyServiceLocator.class)
@ExtraTypes( {
GenericDictionaryProxy.class,
PageIProxy.class,
ContentIProxy.class
} )
public interface GenericDictionaryContext extends GenericContext {
public Request<List<GenericDictionaryProxy>> getListOrderedByName();
}
public interface Services extends RequestFactory {
GenericContext getGenericContext();
GenericDictionaryContext getGenericDictionaryContext();
}
这里是客户端执行实现:
List<GenericDictionaryProxy> proxies = new LinkedList<GenericDictionaryProxy>();
GenericDictionaryContext context = createRequestFactory().getGenericDictionaryContext();
context.get().to(new Receiver<List<GenericDictionaryProxy>>() {
@Override
public void onSuccess(List<GenericDictionaryProxy> response) {
for(GenericDictionaryProxy p: response) {
cont.add(new Label(p.getId() + " " + p.getName() + ", " + p.getVersion() ));
}
}
}).fire();
我应该 return 一个包含参数的对象列表:id、版本、名称。
不幸的是它不起作用。
我的 IDE 显示错误:
Could not find domain method similar to java.util.List<pl.derp.server.model.GenericDictionaryModel<T>> getListOrderedByName() GenericDictionaryContext.java /Index/src/main/java/pl/derp/shared/rf line 26 Annotation Problem (Java 6 processor)
The method to(Receiver<? super List<GenericProxy>>) in the type Request<List<GenericProxy>> is not applicable for the arguments (new Receiver<List<GenericDictionaryProxy>>(){}) GoodbyeViewImpl.java /Index/src/main/java/pl/derp/client/view line 91 Java Problem
编译错误如下:
[INFO] Tracing compile failure path for type 'pl.derp.client.view.GoodbyeViewImpl'
[INFO] [ERROR] Errors in 'file:/home/korbeldaniel/git/derp3/tutorial/src/main/java/pl/derp/client/view/GoodbyeViewImpl.java'
[INFO] [ERROR] Line 91: The method to(Receiver<? super List<GenericProxy>>) in the type Request<List<GenericProxy>> is not applicable for the arguments (new Receiver<List<GenericDictionaryProxy>>(){})
[INFO] [ERROR] Hint: Check the inheritance chain from your module; it may not be inheriting a required module or a module may not be adding its source path entries properly
请告诉我哪里做错了。
是的,这对你有用,但你需要在你的 RequestContext 上为你需要的所有不同类型添加 @ExtraTypes 注释。
我刚才发布了一个完整的例子。
GWT polymorphic lists with @ExtraTypes
编辑
要使其正常工作,您应该让您的通用请求上下文使用泛型。这是我过去所做的,对我来说是正确的。你不需要泛型上的额外类型来完成这项工作,因为你将告诉它类型。
@Service(value = GenericDao.class, locator = MyServiceLocator.class)
public interface GenericContext<T extends GenericProxy> extends RequestContext {
Request<T> getBy(Long id);
Request<List<T>> get();
Request<Void> save(T entity);
}
@Service(value = GenericDictionaryDao.class, locator = MyServiceLocator.class)
@ExtraTypes( {
GenericDictionaryProxy.class,
PageIProxy.class,
ContentIProxy.class
} )
public interface GenericDictionaryContext extends GenericContext<GenericDictionaryProxy> {
public Request<List<GenericDictionaryProxy>> getListOrderedByName();
// These used to be required due to a bug a while ago. Test without it
// but if you get a method about an unknown method then this is the issue.
Request<GenericDictionaryProxy> getBy(Long id);
Request<List<GenericDictionaryProxy>> get();
Request<Void> save(T entity);
}
前段时间我发现了一个问题,不确定是否已修复,但我还必须将方法添加到扩展 class。我不介意,因为我仍然被允许在需要时使用我的 GenericContext 并且一切正常。这使我能够使用 guava LoadingCache 创建一个很好的实体缓存机制。
快速示例。
public class EntityCache<T extends GenericProxy, R extends GenericContext<T>> {
private R requestContext;
public EntityCache(R requestContext) {
this.requestContext = requestContext;
}
public T get(Long key) {
// get from loading cache but this is a simple example.
requestContext.get(key);
}
}
我想知道,是否可以将请求工厂 proxy/context 的通用 类 用于所有实体的通用操作,例如 getById(Long id)
.
在我的应用程序中,我会有很多像 类 这样的词典,它们只有 id
和 name
参数,所以我想编写一次功能并通过继承使用它在休息 类:
服务器实现如下:
领域模型类
@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;
}
}
@MappedSuperclass
public abstract class GenericDictionaryModel<T extends GenericModel<T>> extends GenericModel<T> {
private String name;
@Transient
private String optionDisplayName;
// private boolean active = true;
public String getName() {return name;}
public void setName(String name) {this.name = name;}
// public boolean getActive() {return active;}
// public void setActive(boolean stat) {this.active = stat;}
public String getOptionDisplayName() {return optionDisplayName;}
public void setOptionDisplayName(String optionDisplayName) {this.optionDisplayName = optionDisplayName;}
public GenericDictionaryModel() {
super();
}
public GenericDictionaryModel(Long id, String name) {
super(id);
this.name = name;
}
}
@Entity
public class PageI extends GenericDictionaryModel<PageI> {
@ManyToMany(cascade = CascadeType.ALL)
private List<Content> contents;
/* Getters and Setters */
public List<Content> getContents() {
return contents;
}
public void setContents(List<Content> contents) {
this.contents = contents;
}
}
DAO 类
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<T> get() {
// }
public List<GenericModel<T>> getList() {
List<T> resultList = JPA.em().createQuery("FROM " + entityClass.getSimpleName()).getResultList();
logger.error(resultList.toString());
return JPA.em().createQuery("FROM " + entityClass.getSimpleName()).getResultList();
}
}
public class GenericDictionaryDao<T extends GenericDictionaryModel<T>> extends GenericDao<T>{
private Logger logger = LoggerFactory.getLogger(this.getClass().getCanonicalName());
// public T getBy(Long id) {
// return super.getBy(id);
// }
public List<GenericModel<T>> getByName() {
return super.get();
}
// public List<T> getListOrderedByName() {
// public List<GenericDictionaryModel> getListOrderedByName() {
public List<GenericDictionaryModel> getListOrderedByName2() {
return null;
}
public List<GenericDictionaryModel<T>> getListOrderedByName() {
try {
return JPA.em()
.createQuery("FROM " + entityClass.getSimpleName() + " ORDER BY name")
.getResultList();
} catch (ClassCastException e) {
return new LinkedList<GenericDictionaryModel<T>>();
}
// return null;
}
}
这是共享的实现:
代理:
@ProxyFor(value = GenericModel.class, locator = GenericLocator.class)
public interface GenericProxy extends EntityProxy {
public Long getId();
public void setId(Long id);
public Integer getVersion();
public void setVersion(Integer version);
}
@ProxyFor(value = GenericDictionaryModel.class, locator = GenericLocator.class)
public interface GenericDictionaryProxy extends GenericProxy {
public String getName();
public void setName(String name);
}
@ProxyFor(value = PageI.class, locator = GenericLocator.class)
public interface PageIProxy extends GenericDictionaryProxy {
public List<ContentIProxy> getContents();
public void setContents(List<ContentIProxy> contents);
public static final String Contents = "contents";
}
和上下文/服务:
@Service(value = GenericDao.class, locator = MyServiceLocator.class)
@ExtraTypes( {
GenericProxy.class
} )
public interface GenericContext extends RequestContext {
Request<GenericProxy> getBy(Long id);
Request<List<GenericProxy>> get();
Request<Void> save(GenericProxy entity);
}
@Service(value = GenericDictionaryDao.class, locator = MyServiceLocator.class)
@ExtraTypes( {
GenericDictionaryProxy.class,
PageIProxy.class,
ContentIProxy.class
} )
public interface GenericDictionaryContext extends GenericContext {
public Request<List<GenericDictionaryProxy>> getListOrderedByName();
}
public interface Services extends RequestFactory {
GenericContext getGenericContext();
GenericDictionaryContext getGenericDictionaryContext();
}
这里是客户端执行实现:
List<GenericDictionaryProxy> proxies = new LinkedList<GenericDictionaryProxy>();
GenericDictionaryContext context = createRequestFactory().getGenericDictionaryContext();
context.get().to(new Receiver<List<GenericDictionaryProxy>>() {
@Override
public void onSuccess(List<GenericDictionaryProxy> response) {
for(GenericDictionaryProxy p: response) {
cont.add(new Label(p.getId() + " " + p.getName() + ", " + p.getVersion() ));
}
}
}).fire();
我应该 return 一个包含参数的对象列表:id、版本、名称。
不幸的是它不起作用。
我的 IDE 显示错误:
Could not find domain method similar to java.util.List<pl.derp.server.model.GenericDictionaryModel<T>> getListOrderedByName() GenericDictionaryContext.java /Index/src/main/java/pl/derp/shared/rf line 26 Annotation Problem (Java 6 processor)
The method to(Receiver<? super List<GenericProxy>>) in the type Request<List<GenericProxy>> is not applicable for the arguments (new Receiver<List<GenericDictionaryProxy>>(){}) GoodbyeViewImpl.java /Index/src/main/java/pl/derp/client/view line 91 Java Problem
编译错误如下:
[INFO] Tracing compile failure path for type 'pl.derp.client.view.GoodbyeViewImpl'
[INFO] [ERROR] Errors in 'file:/home/korbeldaniel/git/derp3/tutorial/src/main/java/pl/derp/client/view/GoodbyeViewImpl.java'
[INFO] [ERROR] Line 91: The method to(Receiver<? super List<GenericProxy>>) in the type Request<List<GenericProxy>> is not applicable for the arguments (new Receiver<List<GenericDictionaryProxy>>(){})
[INFO] [ERROR] Hint: Check the inheritance chain from your module; it may not be inheriting a required module or a module may not be adding its source path entries properly
请告诉我哪里做错了。
是的,这对你有用,但你需要在你的 RequestContext 上为你需要的所有不同类型添加 @ExtraTypes 注释。
我刚才发布了一个完整的例子。
GWT polymorphic lists with @ExtraTypes
编辑
要使其正常工作,您应该让您的通用请求上下文使用泛型。这是我过去所做的,对我来说是正确的。你不需要泛型上的额外类型来完成这项工作,因为你将告诉它类型。
@Service(value = GenericDao.class, locator = MyServiceLocator.class)
public interface GenericContext<T extends GenericProxy> extends RequestContext {
Request<T> getBy(Long id);
Request<List<T>> get();
Request<Void> save(T entity);
}
@Service(value = GenericDictionaryDao.class, locator = MyServiceLocator.class)
@ExtraTypes( {
GenericDictionaryProxy.class,
PageIProxy.class,
ContentIProxy.class
} )
public interface GenericDictionaryContext extends GenericContext<GenericDictionaryProxy> {
public Request<List<GenericDictionaryProxy>> getListOrderedByName();
// These used to be required due to a bug a while ago. Test without it
// but if you get a method about an unknown method then this is the issue.
Request<GenericDictionaryProxy> getBy(Long id);
Request<List<GenericDictionaryProxy>> get();
Request<Void> save(T entity);
}
前段时间我发现了一个问题,不确定是否已修复,但我还必须将方法添加到扩展 class。我不介意,因为我仍然被允许在需要时使用我的 GenericContext 并且一切正常。这使我能够使用 guava LoadingCache 创建一个很好的实体缓存机制。
快速示例。
public class EntityCache<T extends GenericProxy, R extends GenericContext<T>> {
private R requestContext;
public EntityCache(R requestContext) {
this.requestContext = requestContext;
}
public T get(Long key) {
// get from loading cache but this is a simple example.
requestContext.get(key);
}
}