RequestFactory 客户端继承类型化 class 与泛型

RequestFactory client-side inheritance of typed class with generics

我想知道,是否可以将请求工厂 proxy/context 的通用 类 用于所有实体的通用操作,例如 getById(Long id).

在我的应用程序中,我会有很多像 类 这样的词典,它们只有 idname 参数,所以我想编写一次功能并通过继承使用它在休息 类:

服务器实现如下:

领域模型类

@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);
    }

}