quinta-feira, 16 de outubro de 2008

Entendendo o padrão de projeto Adapter

Então, faz muito tempo que não posto neste blog, mas agora estou com internet de novo em casa, posso tentar atualizar meu blog com mais freqüência. Vou postar outra coisinha simples, mas que muita gente não conhece, relacionado a padrões de projeto (design patterns), um assunto que eu considero o mais, senão um dos mais importantes para alguém que trabalha com orientação a objetos.

Um padrão de projeto é uma solução comum para um determinado problema, existem 23 padrões "clássicos" para programar orientado a objetos, eles são conhecidos como os 23 padrões GoF (Gang of Four devido as 4 pessoas que criaram eles), além desses 23 padrões clássicos existem ainda padrões J2EE (recomendados pela SUN), padrões GRASP (General Responsibility Assignment Software Patterns) entre outros. Qualquer um pode "criar" um padrão, eles surgem de acordo com a evolução das arquiteturas e do desenvolvimento dos sistemas.

Hoje vou falar de um padrão do GoF que eu costumo usar conhecido como Adapter, esse padrão tem como objetivo converter uma interface de uma classe em outra interface esperada pelos clientes, exemplos da utilização pode ser visto na API padrão do java para tratamento de eventos (MouseAdapter, WindowAdapter), Wrappers (Integer, Double), etc. Existem duas formas de Adapter: Class Adapter que utiliza herança múltipla e Object Adapter que utiliza composição. Class Adapter é usado quando o cliente alvo que eu quero adaptar possui uma interface estatica, Object Adapter é usado quando se deseja menor acoplamento ou quando o cliente alvo que quero implementar não usa interface.

Mas vamos aos códigos. Imagine que estamos utilizando um framework de cinema, que possui uma classe para representar filme, uma interface que define ator, e uma classe que representa o ator principal (só para existir uma implementação de ator). Em um filme eu posso incluir vários atores e então rodar o filme:

public interface Ator {

 void representar();

}

public class Filme {

 private List<Ator> atores = new ArrayList<Ator>();

 public void addAtor(Ator ator) {
  atores.add(ator);
 }

 public List<Ator> getAtores() {
  return Collections.unmodifiableList(atores);
 }

 public void rodaFilme() {
  for (Ator ator : atores) {
   ator.representar();
  }
 }
}

public class AtorPrincipal implements Ator {

 public void representar() {
  System.out.println("Ator principal representando");
 }

}

Essas são classes e interfaces do framework de cinema, eu não posso alterar. Agora imagine que eu tenho meu sistema que possui pessoas, e um comportamento dessas pessoas é andar:

public class Pessoa {

 public void andar() {
  System.out.println("Pessoa andando");
 }

}

Com essa minha classe de pessoa, eu queria incluir figurantes no meu filme, pessoas que não são atores, só para ficar andando lá, fazendo número no filme, porém não posso alterar a interface do filme para receber pessoas, o que eu faço?! Adapto pessoa para ser ator, dessa forma:

public class Figurante1 extends Pessoa implements Ator {

 public void representar() {
  andar();
 }

}

Nesse caso eu usei Class Adapter, pois adaptei a classe pessoa a um ator. Porem esse adaptador não serve para qualquer pessoa, ele é uma nova Pessoa, nova classe, ele não adapta pessoas já existentes a um ator, eu tenho que criar realmente um figurante novo, não adaptar uma pessoa, por isso Class Adapter. Caso você precisasse adaptar qualquer pessoa a um figurante, essa não seria a melhor forma, o ideal é que a classe figurante (adaptadora) fosse dessa forma (usando object adapter):

public class Figurante2 implements Ator {

 private Pessoa pessoa;

 public Figurante(Pessoa pessoa) {
  this.pessoa = pessoa;
 }

 public void representar() {
  pessoa.andar();
 }

}

Ambos são adaptadores, qual usar? Depende do que você quer, em minha opinião, o perfeito é dar as duas opções, eu adaptar uma pessoa já existente ou eu criar uma nova pessoa que já é um figurante, para isso pessoa deveria ter uma interface, e ai meu figurante seria dessa forma:

public class Figurante3 implements Ator, InterfaceDePessoa {

 private InterfaceDePessoa pessoa;

 public Figurante(InterfaceDePessoa pessoa) {
  this.pessoa = pessoa;
 }

 public Figurante() {
  this.pessoa = new Pessoa();
 }

 public void representar() {
  pessoa.andar();
 }

 public void andar() {
  pessoa.andar();
 }

}

Isso me permite adaptar qualquer pessoa a um figurante, bem como criar um novo figurante do "zero", ou seja, é uma junção dos dois figurantes apresentados anteriormente. Mas, meu sistema não tem uma interface de Pessoa e eu não quis criar, então vou usar meus dois primeiros figurantes:

public class Main {

 public static void main(String[] args) {
  Ator a1 = new AtorPrincipal();  //um ator de verdade
  Figurante f1 = new Figurante1();  //uma nova pessoa que ja nasceu Figurante
  Pessoa p1 = new Pessoa();  //uma pessoa normal
  Figurante f2 = new Figurante2(p1);  //a pessoa normal adaptada a figurante

  Filme filme = new Filme();
  filme.addAtor(a1);
  filme.addAtor(f1);
  filme.addAtor(f2);

  filme.rodaFilme();
 }

}

Agora vamos evoluir, achei um framework que gerencia tarefas, e eu quero incluir tarefas que ao serem executadas fazem com que todos os atores do filme representem. Esse framework tem uma classe abstrata que representa uma tarefa e um gerente de tarefas:

public abstract class Tarefa {

 public abstract void executar();

}

public class GerenteTarefa {

 public void executar(List<Tarefa> tarefas) {
  for (Tarefa tarefa : tarefas) {
   tarefa.executar();
  }
 }

}

Mas repare que não tenho uma interface de tarefa, então como vou adaptar atores (qualquer ator, até mesmo o figurante) a tarefas?! Solução: Object adapter, ou seja, vou criar meu adaptador a partir de objetos com composição (mesma idéia do figurante2, pois eu quero adaptar qualquer ator a tarefas):

public class AdaptadorDeAtor extends Tarefa {

 private Ator ator;

 public AdaptadorDeAtor(Ator ator) {
  this.ator = ator;
 }

 public void executar() {
  ator.representar();
 }

}

Repare que eu não adaptei a classe, meu adaptador não é um novo ator, ele é uma tarefa que delega seu método “executar” para um objeto de ator, ele adapta qualquer ator a tarefa, executando isso:

public class Main {

 public static void main(String[] args) {
  Ator a1 = new AtorPrincipal();  //um ator de verdade
  Figurante f1 = new Figurante1();  //uma nova pessoa que ja nasceu Figurante
  Pessoa p1 = new Pessoa();  //uma pessoa normal
  Figurante f2 = new Figurante2(p1);  //a pessoa normal adaptada a figurante

  Filme filme = new Filme();
  filme.addAtor(a1);
  filme.addAtor(f1);
  filme.addAtor(f2);

  filme.rodaFilme();

  List<Tarefa> tarefas = new ArrayList<Tarefa>();
  for (Ator ator : filme.getAtores()) {
   tarefas.add(new AdaptadorDeAtor(ator));
  }

  GerenteTarefa gt = new GerenteTarefa();
  gt.executar(tarefas);
 }

}

Ou seja, consegui adaptar minha classe Pessoa para um ator e depois adaptei um ator para tarefa, usando Class e Object Adapter. Entendendo isso, você consegue adaptar qualquer classe para praticamente qualquer interface, talvez muita gente já fez isso, mas não sabia que tinha nome. Para quem nunca usou, pense bem, pode ser muito útil na reutilização de código, integrar sistemas e pode ajudar bastante a melhorar o desenvolvimento.

segunda-feira, 26 de maio de 2008

Scrum, meu novo interesse

Semana passada eu fiz um curso de scrum na caelum, eu não tenho tempo nem conheço tanto para explicar como funciona scrum em geral, mas as impressões que fiquei foram muito, mas muito boas mesmo.

Parece uma metodologia que, ao mesma tempo da muita liberdade para o time (desenvolvedores), mas é cruel com pessoas que não rendem, os espertinhos, “enroladores”, pois a cobrança não vem de cima, vem dos lados, dos próprios companheiros de time. A metodologia é baseada muito na confiança da equipe, é uma confiança controlada através de reuniões diárias, mas que faz com que o desenvolvedor se sinta bem desenvolvendo. O scrum me parece realista para a maioria dos problemas de desenvolvimento de sistemas e alguns sociais que podem existir em uma equipe, nele você sabe que o cliente vai mudar os requisitos, você sabe que o programador não vai cumprir exatamente o tanto de horas que ele orçou, trabalha muito com feedback, sinceridade entre a equipe e o mais fantástico, a própria metodologia oferece recursos que ajudam a trabalhar e melhorar isso, como as reuniões diárias e retrospectiva, tudo visando o bem da equipe e não apenas da pessoa. Acho que o sentimento de alguém que trabalha dessa forma é: “eu prefiro ser o goleiro do time vencedor do campeonato, do que um excelente goleiro de um time rebaixado”.

Bom, estamos tentando adotar scrum aqui na empresa (já eheh), o que o Alexandre (nosso instrutor) disse na aula parece que aconteceu, santo de casa não faz milagres, embora agente explique e as pessoas estudem a metodologia, elas duvidam que funcione, por mais que você fala, elas duvidam e querem até mesmo mudar a forma como scrum é, impondo mais responsabilidades de controle da equipe ao scrum master, mudando o planning poker, mudando a reunião de planejamento, enfim, alterando a forma como scrum trabalha, inserindo itens que acabam com toda a vantagem que a metodologia oferece. Mas, eu estou bem confiante, consegui passar a importância de se seguir a metodologia, o porque que é assim, e no fim, acho que vamos seguir o planejado e o certo, espero dar tudo certo e provar que realmente funciona.

Sobre o curso eu aconselho todos que façam porque realmente é bom, scrum é uma metodologia simples, com técnicas bem sociais e realistas, mas que se for pensar bem, é ideal para desenvolvimento de sistemas.

Ai a foto da galera que participou do treinamento (roubada do blog do Alexandre):

sexta-feira, 25 de janeiro de 2008

Criando um Scope ThreadLocal no Guice

Eu comecei a estudar um pouco o Guice, que é um framework da google de injeção de dependência. Estava fazendo uns testes e queria ter uma forma de que o Guice me retornasse sempre a mesma instância quando solicitar um objeto na mesma thread, algo como se feito com esse Factory:

public class ServiceFactory {

 private static ThreadLocal<Service> tl = new ThreadLocal<Service>();

 public static Service get() {
  Service t = tl.get();
  if (t == null) {
   t = new ServiceImpl();
   tl.set(t);
  }
  return t;
 }
}
Porém não achei um scope para isso (na real procurei bem pouco). Resolvi, até para aprendizado criar um novo scope para que seja ThreadLocal, até que deu certo, eis o resultado:
import com.google.inject.Key;
import com.google.inject.Provider;
import com.google.inject.Scope;
...

class LocalThreadScope implements Scope {
 public <T> Provider<T> scope(Key<T> key, final Provider<T> provider) {
  return new Provider<T>() {
   ThreadLocal<T> tl = new ThreadLocal<T>();

   public T get() {
    T t = tl.get();
    if (t == null) {
     t = provider.get();
     tl.set(t);
    }
    return t;
   }
  };
 }

 @Override
 public String toString() {
  return "ThreadLocalScope";
 }
}
Usando-se esse Scope para fazer o bind, o Guice ira criar um novo objeto para cada thread diferente. Exemplo:
public interface Service {
 void go();
}

public class ServiceImpl implements Service {
 public void go() {
  System.out.println(this + " - " + Thread.currentThread());
 }
}

public class MyModule implements Module {
 public void configure(Binder binder) {
  binder.bind(Service.class).to(ServiceImpl.class).in(
    new LocalThreadScope());
 }
}


public class Main {
 public static void main(String[] args) {
  final Injector inj = Guice.createInjector(new MyModule());
  Service s = inj.getInstance(Service.class);
  s.go();
  s = inj.getInstance(Service.class);
  s.go();
  Runnable r1 = new Runnable() {
   public void run() {
    Service s = inj.getInstance(Service.class);
    s.go();
   }
  };
  new Thread(r1).start();
 }
}


quarta-feira, 5 de dezembro de 2007

Herança múltipla no Java

É um assunto já bem manjado, milhões de explicações pela internet, mas sempre aparece alguém dizendo que Java não tem herança multipla. Bem, é verdade, não existe, mas isso não quer dizer que não da para fazer. Segue um exemplo de como da para fazer herança múltipla com Java utilizando interfaces e agregação.

Considere uma interface que define um animal, não vou complicar enxendo de métodos, portanto vou tentar ser o mais simples possivel. Todo animal come portanto essa interface irá definir um método comer:

Animal.java

public interface Animal {
 void comer();
}

Vou criar agora duas novas interfaces, uma que define gatos e outra que define cachorros, sendo que ambas são animais também (claro).

Gato.java

public interface Gato extends Animal {
    void miar();
}
Cachorro.java
public interface Cachorro extends Animal {
    void latir();
}

Feito isso, implemento duas classes concretas: um gato (o gato siamês) e um cachorro (pastor alemão). Até ai tudo bem, nada de diferente ou de herança múltipla.

GatoSiames.java

public class GatoSiames implements Gato {
    public void miar() {
        System.out.println("miando");
    }
    
    public void comer() {
        System.out.println("gato comendo");
    }
}
PastorAlemao.java
public class PastorAlemao implements Cachorro {
    public void latir() {
        System.out.println("latindo");
    }
    
    public void comer() {
        System.out.println("cachorro comendo");
    }
}

Agora sim, começaremos as bizarrices, supondo que meu pastor alemão se engraçou com uma gata siamesa, no meu mundo isso é possível. No meu mundo também, a mãe é que da a característica principal do filho, ou seja, qualquer criatura que nasce de uma gata vai se parecer mais com um gato e qualquer coisa que nasce de uma cadela vai se parecer mais um cachorro. Logo, de acordo com as regras do meu mundo, quando o pastor alemão cruzou com a gata siamesa, nasceu uma criatura que se parece com um gato siamês, mas tem também características de um pastor alemão, ou seja, ela tem que herdar comportamento de ambas classes, mas as características de animal (comer), isso ela herda da mãe mesmo. Veja como usando interface e agregação é fácil modelar essa espécie bizarra:

GatoBizarro.java

public class GatoBizarro extends GatoSiames implements Cachorro {
    private PastorAlemao cachorro = new PastorAlemao();
    
    public void latir() {
        cachorro.latir();
    }
}

Perceba que se eu mandar esse bixo comer, ele vai comer feito um gato, na real ele pode ser considerado um gato pois sabe miar. Porem como é um filho de um cachorro, ele pode ser considerado como cachorro também pois sabe latir (e lati feito um pastor alemão), mas mesmo olhando para ele como um cachorro, comer que é o comportamento em comum entre todos animais, isso ele faz como um gato mesmo.

Agora vamos fazer o contrario, um gato siamês pulou a cerca com uma pastora alemã (como ele deu conta, ninguém sabe). Como eu já disse, quem manda na característica principal é a fêmea, logo nasceu algo parecido com cachorro. Eis a classe que representa essa criatura:

public class CachorroBizarro extends PastorAlemao implements Gato {
    private GatoSiames gato = new GatoSiames();
    
    public void miar() {
        gato.miar();
    }
}

Esse cara ai come feito cachorro, lati feito cachorro, mas sabe miar feito um gato siamês ;).

Viu como é fácil, usando de agregação e delegando ao objeto agregado é possível e fácil fazer herança múltipla com Java.

quinta-feira, 22 de novembro de 2007

Fazendo qualquer consulta ao banco de forma paginada.

Como eu imaginava, não tenho tempo para olhar muito isso e fazer novas postagens, mas juro que vou tentar melhorar hehe.

Já tem um tempo to devendo postar isso, é uma solução que fiz e uso para paginação no acesso a dados. Ela surgiu quando eu tinha que ler muitas tabelas e muitos registros de cada uma, o que gerava um OutOfMemory, então eu quis criar uma forma de que qualquer sql que eu executasse, ou até mesmo qualquer acesso a objetos (como por exemplo lendo de um XML, ou arquivo) que eu tivesse suporte a paginação de dados. Mas eu queria que isso fosse feito de forma transparente, ou seja, pudesse tratar esse retorno em for each do Java 5 por exemplo.

Não vou entrar em detalhes da implementação, mesmo porque não tem nada complexo, vou postar os códigos e um comentário simples apenas.

Esta é a interface de acesso que suporta paginação, todos meus objetos devem ser acessados a partir dessa interface, logo toda implementação que busca objetos (do banco, de arquivos, etc) implementa essa interface

public interface DataSet<T> extends Iterable<T> {

 List<T> list(int firstResult, int maxResults);

 List<T> listAll();

 int size();
}

O negócio é simples, apenas três métodos, um que exige suporte paginado, um que possibilita listar tudo e o ultimo que retorna o tamanho, além de estender Iterable (para eu que possa dar o for each). A próxima classe é justamente uma que implementa Iterable para poder ser usado em um DataSet:

public class DataSetIterator<T> implements Iterator<T> {

 private final DataSet<T> dataSet;
 
 private final int cacheSize;

 private List<T> cacheData;
 
 private int currentIt;
 
 private int totalReaded;

 public DataSetIterator(DataSet<T> dataSet, int cacheSize) {
  if (cacheSize <= 0 || dataSet == null) {
   throw new IllegalArgumentException();
  }
  this.dataSet = dataSet;
  this.cacheSize = cacheSize;
  this.currentIt = 0;
 }

 public boolean hasNext() {
  if (currentIt >= cacheSize || cacheData == null) {
   cacheData = dataSet.list(totalReaded, cacheSize);
   currentIt = 0;
  }
  return cacheData.size() > currentIt;
 }

 public T next() {
  if (hasNext()) {
   totalReaded++;
   return cacheData.get(currentIt++);
  } else {
   throw new NoSuchElementException();
  }
 }

 public void remove() {
  throw new UnsupportedOperationException();
 }
}

A próxima classe é só uma abstração de DataSet que implementa os métodos exigidos pela interface Iterable, no caso usando o Iterator criado anteriormente

public abstract class AbstractDataSet<T> implements DataSet<T> {
 public Iterator<T> iterator() {
  return new DataSetIterator<T>(this, 50);
 }
}

Agora vou criar duas classes que serão úteis para meus DataSet's que acessam o banco de dados. A primeira classe é justamente a implementação de um DataSet mas que lê dados uma List do Java, isso vai ser útil para caso seja utilizado o método listAll de algum DataSet que acessa o banco, nas próximas consultas ao mesmo DataSet não será mais lido do banco (pois já leu tudo) e sim de uma lista em memória (DataSet de lista).

public class ListDataSet<T> extends AbstractDataSet<T> {

 private final List<T> list;

 public ListDataSet(List<T> list) {
  if (list == null) {
   throw new IllegalArgumentException();
  }
  this.list = list;
 }

 public List<T> list(int firstResult, int maxResults) {
  if (firstResult > list.size()) {
   return new ArrayList<T>();
  }
  if (firstResult < 0 || maxResults <= 0) {
   return list;
  }
  int toIndex = Math.min(firstResult + maxResults, list.size());
  return list.subList(firstResult, toIndex);
 }

 public int size() {
  return list.size();
 }

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

A segunda é uma interface, sua função é como se fosse um Factory. Vai servir para obter o Criteria quando fizer um DataSet que usa Criteria do Hibernate ou obter a Query quando fizer um DataSet que usa Query do JPA.

public interface Provider<T> {
 
 T get();

}

Agora sim, finalmente os DataSet's que fazem acesso ao banco de dados. O primeiro serve para fazer consultas usando ejbql do JPA. Ele recebe dois providers (fabricas, como você achar melhor), um para obter a Query da consulta em si e outro para obter a Query que busca a quantidade de registros (um count da consulta não paginada).

public class JpaQueryDataSet<T> extends AbstractDataSet<T> {

 private Integer size;

 private ListDataSet<T> listDs;

 private final Provider<Query> queryProvider;

 private final Provider<Query> countQueryProvider;

 public JpaQueryDataSet(Provider<Query> queryProvider,
   Provider<Query> countQueryProvider) {
  if (queryProvider == null || countQueryProvider == null) {
   throw new IllegalArgumentException();
  }
  this.size = null;
  this.listDs = null;
  this.queryProvider = queryProvider;
  this.countQueryProvider = countQueryProvider;
 }

 @SuppressWarnings("unchecked")
 public List<T> list(int firstResult, int maxResults) {
  if (listDs != null) {
   return listDs.list(firstResult, maxResults);
  } else {
   final Query query = queryProvider.get();
   if (firstResult < 0 || maxResults <= 0) {
    final List<T> list = query.getResultList();
    size = list.size();
    listDs = new ListDataSet<T>(list);
    return list;
   } else {
    query.setFirstResult(firstResult);
    query.setMaxResults(maxResults);
    final List<T> list = query.getResultList();
    return list;
   }
  }
 }

 public int size() {
  if (size == null) {
   final Query query = countQueryProvider.get();
   size = ((Long) query.getSingleResult()).intValue();
  }
  return size;
 }

 public List<T> listAll() {
  return list(-1, -1);
 }
}

Esse segundo DataSet serve para fazer consultas usando criteria do Hibernate. Ele recebe um provider justamente para obter o Criteria:

public class HibernateCriteriaDataSet<T> extends AbstractDataSet<T> {

 private Integer size;

 private ListDataSet<T> listDs;

 private final Provider<Criteria> criteriaProvider;

 public HibernateCriteriaDataSet(Provider<Criteria> criteriaProvider) {
  if (criteriaProvider == null) {
   throw new IllegalArgumentException();
  }
  this.criteriaProvider = criteriaProvider;
 }

 @SuppressWarnings("unchecked")
 public List<T> list(int firstResult, int maxResults) {
  if (listDs != null) {
   return listDs.list(firstResult, maxResults);
  } else {
   final Criteria crit = criteriaProvider.get();
   if (firstResult < 0 || maxResults <= 0) {
    final List<T> list = crit.list();
    size = list.size();
    listDs = new ListDataSet<T>(list);
    return list;
   } else {
    crit.setMaxResults(maxResults);
    crit.setFirstResult(firstResult);
    return crit.list();
   }
  }
 }

 public List<T> listAll() {
  return list(-1, -1);
 }

 public int size() {
  if (size == null) {
   final Criteria crit = criteriaProvider.get();
   crit.setProjection(Projections.rowCount());
   size = (Integer) crit.uniqueResult();
  }
  return size;
 }
}

Claro que nem todas consultas você vai conseguir fazer usando isso, então encare mais como um utilitário. Segundo é, para esses DataSet que acessam banco de dados, óbvio que precisa ser executado em um contexto transacional.

Para comprovar que funciona, criei uma tabela cargo com id e nome, e inseri alguns registros. Buscando todos registros através de um DataSet, fazendo um for each mandando meu iterator ler paginado de 5 em 5 (configuravel dentro de AbstractDataSet) e exibindo por primeiro o número de registros da consulta. Perceba que a cada 5 registros lidos um novo sql é executado para buscar os próximos (claro que 5 é um número muito pequeno para paginar, aqui estou usando só como exemplo, edite AbstractDataSet de acordo com suas necessidades ou até mesmo deixe isso configuravel nas sub classes):

DataSet<Cargo> ds = Cargo.findAll();
  System.out.println(ds.size());
  for (Cargo c : ds) {
   System.out.println(c.getName());
  }
Console:
Hibernate: select count(*) as col_0_0_ from cargo cargo0_
332
Hibernate: select cargo0_.cd_cargo as cd1_0_, cargo0_.nm_cargo as nm2_0_ from cargo cargo0_ limit ?
Account Manager
Administrador(a)
Administrador(a) Banco de Dados
Administrador(a) Empresas
Administrador(a) Materiais
Hibernate: select cargo0_.cd_cargo as cd1_0_, cargo0_.nm_cargo as nm2_0_ from cargo cargo0_ limit ?, ?
Administrador(a) Rede
Advogado(a)
Agente Administrativo
Agente Comercial
Agente Compras
Hibernate: select cargo0_.cd_cargo as cd1_0_, cargo0_.nm_cargo as nm2_0_ from cargo cargo0_ limit ?, ?
Agente Financeiro
Agente Negócios
...

Segue o que seria a implementação do método findAll. Esse primeiro usando o HibernateCriteriaDataSet:

final Session session = //obtem o Session, seja via Spring, ou como vc quiser
   final Provider<Criteria> crit = new Provider<Criteria>() {
    public Criteria get() {
     return session.createCriteria(Cargo.class);
    }
   };
   return new HibernateCriteriaDataSet<Cargo>(crit);
E esse segundo usando JpaQueryDataSet:
final EntityManager entityManager =  //obtem o EntityManager, seja via Spring, ou como vc quiser
   final String sql = "select e from " + Cargo.class.getName() + " e";
   final String countSql = "select count(*) from "
     + Cargo.class.getName() + " e";
   final Provider<Query> queryProvider = new Provider<Query>() {
    public Query get() {
     return entityManager.createQuery(sql);
    }
   };
   final Provider<Query> countQueryProvider = new Provider<Query>() {
    public Query get() {
     return entityManager.createQuery(countSql);
    }
   };
   return new JpaQueryDataSet<Cargo>(queryProvider, countQueryProvider);

Bem, eu não postei, mas já fiz implementações dessas que acessam objetos em xml e até mesmo um DataSet que lê paginado de outros DataSet's (por exemplo fazer um for each que lê de um banco de dados e de um arquivo xml de forma transparente e paginada). Pode ser que exista soluções muito melhores, mas na época não tinha achado nada que fizesse o que eu queria, por isso criei esse jeito, o que vem me quebrando um bom galho ultimamente.