2010-07-22 6 views
1

J'emprunte la signification de «tranche» de C++.Comment «découper» un POJO

Disons que je Hava simple POJO qui est persisté via Hibernate:

class Person { 
private long id; 
private String name; 
... 
// getters and setters here 
... 
} 

Maintenant, lorsque je récupère un objet à partir de la base de données, je sais qu'il a été « instrumentée » par Hibernate (sa classe réelle est une personne- dérivé généré automatiquement). Je veux le convertir en un objet personne "simple". Tnat serait utilisé, par exemple, pour soumettre l'objet à XStream et avoir le résultat contenant uniquement ce que contient Person. Je pourrais le faire en définissant un constructeur de copie, mais je ne veux pas avoir le tracas d'avoir à écrire des constructeurs de copie pour chaque classe ORM (sans parler de la violation du principe DRY).

Je me demandais si

a) est-il déjà une lib Java qu'il fait? b) Si non, serait-il pratique d'en écrire un en utilisant la réflexion?

Dans le cas de (b), des recommandations/directives/squelettes de code seraient appréciés.

Répondre

3

La bibliothèque de cartographie de haricots Dozer fait un excellent travail de cela et est mort simple à utiliser.

il suffit simplement une instance de la fève retournée par Hibernate à sa propre classe:

Person person = session.load(...); 
BeanMapper mapper = ...; 
Person cleanPerson = mapper.map(person, Person.class); 

le tour est joué, plus Hibernate procurations ou des collections chargées paresseux!

+0

C'est une solution parfaite. Il résout même un autre problème que je n'ai pas mentionné, le fait que les relations un-à-plusieurs doivent être représentées comme des conteneurs dans l'objet persistant et comme des tableaux dans l'objet XML-ed. Merci beaucoup. –

+0

Le but réel de Dozer est de mapper de TypeA à TypeB, et de pouvoir stocker ce mapping dans les configs XML plutôt que dans le code Java, donc ce serait parfait pour cette utilisation aussi (vraiment mappage d'un type à un autre). –

1

La classe org.apache.commons.beanutils.BeanUtilsBean fait probablement presque tout ce que vous voulez. La méthode copyProperties passera par l'appel des getters sur votre Entité et la recherche de setters avec un nom de propriété correspondant sur un objet cible que vous fournissez. Vous devrez peut-être gérer certaines entités imbriquées, selon le type de comportement que vous voulez et si/comment vous mappez les relations.

Si vous avez besoin d'être plus sophistiqué, vous pouvez enregistrer un convertisseur pour transformer vos types d'entités imbriqués en quelque chose d'autre.

+0

Merci. Il résout le problème partiellement. Mais je pensais plus à une méthode comme mybject = Slicer.slice (myObject, Person.class). Cela créerait un nouvel objet Person (en appelant newInstance sur le deuxième paramètre) et le traverserait pour savoir quoi copier. De cette façon, j'éviterais complètement le besoin d'écrire du code spécifique à chaque cas. –

0

Vous pourriez avoir une classe de personne sans information de persistance enveloppé par une contrepartie persistante, comme ceci:

public class Person implements Serializable 
{ 
    private String name; 
    // others. 
} 

public class PersistentPerson 
{ 
    private Long id; 
    private Person data; // 

    public Person getPerson() { return this.data; } 
} 

Je ne suis pas sûr que la conception est la peine. Le double modèle me fait un peu vomir, juste en écrivant cet exemple. La plus grande question est: Pourquoi pensez-vous que cela est nécessaire? S'il n'y a pas de bon moyen de dire à XStream de ne pas inclure le id lors de la sérialisation, je dirais qu'il vaudrait mieux écrire le vôtre javax.xml.bind.Marshaller et javax.xml.bind.Unmarshaller pour obtenir ce que vous voulez.

Il existe de meilleures façons de résoudre ce problème que de bastardiser l'ensemble de votre conception.

+0

Merci, mais ce serait plus de travail (et aussi rendre le code moins lisible) que de faire un simple constructeur de copie ou de rendre les deux objets indépendants comme Pete suggéré. –

+0

La personne est complètement indépendante de PersistentPerson. Vous devez avoir au moins une relation à sens unique. Personnellement, je pense que la séparation des couches n'est pas si importante que ça. – duffymo

1

Il y a une discussion intéressante sur votre problème ici

http://www.mojavelinux.com/blog/archives/2006/06/hibernate_get_out_of_my_pojo/

Plusieurs solutions sont proposées dans les commentaires. En particulier

http://code.google.com/p/entity-pruner/

http://www.anzaan.com/2010/06/serializing-cglib-enhanced-proxy-into-json-using-xstream/

Je suis personnellement énorme sur la séparation des couches, et je dirais que les classes que vous souhaitez sérialiser à travers le fil ou XML devraient effectivement être séparés de vos classes de couche d'accès aux données , ce qui permettrait également de résoudre le problème.

class SerializablePerson 
{ 
    ... fields you care about ... 
    SerializablePerson(Person person) 
    { 
     ... set only what you care about ... 
    } 

}