2011-12-12 4 views
2

내 Java 프로젝트의 페이지 매김 시스템에서 작업 중이므로 다양한 JPA 모델에 대해 일반화하고 싶습니다.일반 클래스 및 메서드

문제는 (내가 아는 한) 제네릭을 사용하면 반환 된 최종 값을 캐스팅해야만 문제를 해결할 수 있습니다. 어떻게 피할 수 있습니까?

여기 내 코드는 지금까지의 (절대적으로 일반적인하지!) :

public interface Paginator { 
    public void setLimit(Integer limit); 
    public Page page(Integer page); 
} 


public class PicturesPaginator implements Paginator { 
    private Integer limit = 10; 
    private JPAQuery query; 
    private Long quantity; 

    public PicturesPaginator(String query, Object... params) { 
     this.query = Picture.find(query, params); 
     this.quantity = Picture.count(query, params); 
    } 

    @Override 
    public void setLimit(Integer limit) { 
     this.limit = limit; 
    } 

    @Override 
    public PicturesPage page(Integer page) { 
     if (page == null) 
      page = 1; 

     List<Picture> pictures = query.fetch(page, limit); 
     return new PicturesPage(pictures, quantity, page, limit); 
    } 
} 


public abstract class Page { 
    protected List<Picture> pictures; 
    protected Long quantity; 
    protected Integer page; 
    protected Integer limit; 

    public List<Picture> list() { 
     return pictures; 
    } 

    public Long count() { 
     return quantity; 
    } 

    public boolean hasNext() { 
     return (page * limit > quantity); 
    } 

    public boolean hasPrevious() { 
     return (page != 1); 
    } 

    public boolean hasOtherPages() { 
     return (hasNext() || hasPrevious()); 
    } 

    public Integer nextPageNumber() { 
     if (!hasNext()) 
      return null; 

     return (page + 1); 
    } 

    public Integer previousPageNumber() { 
     if (!hasPrevious()) 
      return null; 

     return (page - 1); 
    } 

    public Integer currentPageNumber() { 
     return page; 
    } 
} 


public class PicturesPage extends Page { 
    public PicturesPage(List<Picture> pictures, Long quantity, Integer page, Integer limit) { 
     this.pictures = pictures; 
     this.quantity = quantity; 
     this.page = page; 
     this.limit = limit; 
    } 
} 

내가 그 PicturesPaginatorPicturesPage하고 일반적인하게 제거하고 싶지만, 추상 클래스 페이지에서 list() 방법은 반환 일반 목록 (여기서 Play를 사용하기 때문에 List<T> 또는 List<GenericModel>) 필자가 생각하기에이 list() 메서드를 사용하면 내 목록에 올바른 목록 인 List<Picture>을 반환 할 수 있습니다. 이것이 가능한가 ?

참고 : 이제 Play에서 페이지 매김을위한 모듈이 있습니다! 프레임 워크, 내 질문은 주로 자바에 대한 자세한 내용을 이해하기위한 것입니다 :)

정말 고마워, 정말 고마워!

답변

3

내 P lay - 페이지 매김 (sage) 모듈의 소스 코드. 나는 source on github을 넣었다.

public class Page<T> { 
    public List<T> list() {} 
} 

대신 PicturesPage의 당신이 단지 수 :

new Page<Picture>() 

페이지 배열 인터페이스는 것 당신이 원하는 무엇

페이지를 만들 일반적인뿐만 아니라, 아마 비 추상적이다 총화해야합니다 :

public interface Paginator { 
    public Page<T> page(Integer page); 
} 

그림 생성하기 당신이 Picture 클래스에서 메서드를 호출합니다. Java의 제네릭 구현은 런타임에 유형을 지우므로 유형 토큰 및 리플렉션을 처리해야합니다.

+0

도움 주셔서 감사합니다. Picture 클래스에서 사용한 것을 본 것은 이해하지 못합니다 : JPA의 항목 만 사용합니다 (찾기 및 개수). 그러나 마지막으로 T를 사용하는 제네릭 클래스가 GenericModel을 확장 할 수 있도록 코드를 업그레이드했는데 문제가 있습니다. 클래스 typeToken = ...이 오류를 발생시킵니다. java.lang.Class를 java.lang.reflect로 형변환 할 수 없습니다. .ParameterizedType'. 내가 도대체 ​​뭘 잘못하고있는 겁니까? –

+0

Re : 그림 클래스, 클래스 메서드를 찾고 있었고 Play를 계산했습니다. 당신을 위해 제공합니다. Re : ClassCastException - 위에서 설명한 것처럼 PicturesPaginator를 만들지 않았다고 가정합니다. 매개 변수가있는 유형을 제공하는 일반 기본 클래스를 확장하는 하위 클래스를 사용합니다 ("PicturesPaginator extends GenericPaginator extends the Example of this"). 다른 방법은 Class typeToken 메서드 매개 변수를 GenericPaginator의 생성자에 추가하는 것입니다. –

+0

당신은 올바르게 추측했습니다! :) 나는 PicturePaginator의 내용을 Page로 옮겨 모든 것을 하나의 클래스로 옮기려고했습니다. 마침내 내 모델에 직접 작업을 추가하고 JPAQuery (find()의 결과), Long (count()의 결과)과 같은 매개 변수를 사용하여 Page를 호출하기로 결정했습니다. 그것은 깔끔한 것은 아니지만 적어도 작동합니다. 당신의 도움을 주셔서 감사합니다 :) –

1

올바른 목록 ( 일명 나의 경우 목록)을 반환하는이 list() 메서드가 무엇을 기대합니까? 이것이 가능한가?

제네릭을 올바르게 사용하면 자동으로 그게 가능하지 않습니다. 당신이

public class Page<T extends GenericModel>{ 
    protected List<T> items; 

    public List<T> list() { 
     return items; 
    } 
} 

를 선언하고 다음과 같이 사용할 경우 : T은 구체적인 유형으로 교체하는 유형 매개 변수 때문에

page = new Page<Picture>(); 

다음 page.list()는 사실, List<Picture> 반환 할 때 Page 선언됩니다.

1

올바르게 이해하면 다음 내용이 도움이 될 수 있습니다.

페이스를 제네릭으로 만드십시오. 돌려

public abstract class Page { 
    protected List<Picture> pictures; 

    public List<Picture> list() { 
     return pictures; 
    } 

에 :

public abstract class Page<Element> { 
    protected List<Element> elements; 

    public List<Element> list() { 
     return elements; 
    } 

PicturesPage의 미장하기보다이 당신이 무엇을 필요로하는 경우

public class PicturesPage extends Page<Picture> { 
1

잘 모르겠어요,하지만이 페이지 클래스를 변환 할 수 있습니다 :

public abstract class Page<T> { 
    protected List<T> pictures; 
    protected Long quantity; 
    protected Integer page; 
    protected Integer limit; 

    public List<T> list() { 
     return pictures; 
    } 

    public Long count() { 
     return quantity; 
    } 

    public boolean hasNext() { 
     return (page * limit > quantity); 
    } 

    public boolean hasPrevious() { 
     return (page != 1); 
    } 

    public boolean hasOtherPages() { 
     return (hasNext() || hasPrevious()); 
    } 

    public Integer nextPageNumber() { 
     if (!hasNext()) 
      return null; 

     return (page + 1); 
    } 

    public Integer previousPageNumber() { 
     if (!hasPrevious()) 
      return null; 

     return (page - 1); 
    } 

    public Integer currentPageNumber() { 
     return page; 
    } 
1

정확하게 이해하면 제네릭 도입과 렘 여기에 다음과 같은 라인 : 현재 반사를 사용해야 할 것입니다, 그래서

this.query = Picture.find(query, params); 

는 AFAIK 당신이 직접 일반적인 유형의 정적 메서드를 호출 할 수 없습니다.이 경우 매개 변수 유형의 클래스를 매개 변수로 전달하거나 (존재하는 경우 리플렉션 데이터에서 가져 오는) 호출하고 호출 할 메소드를 찾아야 할 수도 있습니다. 일반 Paginator에 "찾기"개체를 전달하고는 find(...)count(...) 방법을 제공하는 인터페이스를 구현하게,

Class<T> clazz; 

public Paginator (Class<T> clazz) { 
    this.clazz = clazz; 

    //note that you need to handle exceptions, I'll leave them out for brevity 
    Method findMethod = clazz.getMethod("find", String.class, Array.class); 
    this.query = findMethod.invoke(null, query, params); 
} 

편집

대안으로 :

그것은이 같은 뭔가 :

interface Finder<T> { 
    JPAQuery find(String query, Object... params); 
    Long count(String query, Object... params); 
} 

class Paginator<T, F extends Finder<T>> { 
    public Paginator(F finder, String query, Object... params) { 
    this.query = finder.find(query, params); 
    ... 
    } 

    ... 
}