Prenons une entité avec uniquement des annotations basiques:

@Entity
@Table(name="person")
public class Person implements Serializable {
    @Id
    @Column(name = "ID")
    private Integer id;
    @Column(name = "LASTNAME")
    private String lastname;
    @Column(name = "FIRSTNAME")
    private String firstname;
    @Column(name = "VERSION")
    private Integer version;
    @Lob
    @Basic(fetch = FetchType.LAZY)
    @Column(name = "REMARKS")
    private String remarks;

    /* getter & setters */
}

Dans mon bean, je met simplement à jour les différents champs de l'entité:

public class ModifierBean implements ModifierBeanLocal {

    @Resource
    private UserTransaction userTransaction;

    @PersistenceContext
    private EntityManager entityManager;

    @Override
    public String modify(Integer id, String lastname, String firstname, String remarks) {
        try {
            StringBuilder result = new StringBuilder(256);

            userTransaction.begin();
            Query query = entityManager.createQuery("SELECT p FROM Person p WHERE p.id = ?1");
            query.setParameter(1, id);

            Person p = (Person)query.getSingleResult();
            result.append("State 0: lastname=").append(p.getLastname()).append(", firstname=").append(p.getFirstname()).append(", version=").append(p.getVersion()).append("<br />");

            p.setFirstname(firstname);
            p.setLastname(lastname);
            p.setVersion(p.getVersion()+1);
            result.append("State 1: lastname=").append(p.getLastname()).append(", firstname=").append(p.getFirstname()).append(", version=").append(p.getVersion()).append("<br />");

            p.setRemarks(remarks); //  <= reset the other fields
            result.append("State 2: lastname=").append(p.getLastname()).append(", firstname=").append(p.getFirstname()).append(", version=").append(p.getVersion()).append("<br />");

            userTransaction.commit();
            return result.toString();
        } catch(Exception e) {
            //...
        }
    }
}

Voici l'output obtenu lorsque le morceau de code ci-dessus est exécuté:

State 0: lastname=Smith, firstname=John, version=0
State 1: lastname=John2, firstname=Smith2, version=1
State 2: lastname=Smith, firstname=John, version=0

Entre l'état 0 et 1, tout est normal, les champs sont bien mis à jour. Par contre, dès que l'appel à setRemarks est effectué, les autres champs sont réinitialisés ! Ce comportement est totalement silencieux, à moins d'activer les logs EclipseLink (et encore, il n'y a pas d'erreur explicite, c'est donc très difficile à explorer).

Pour avoir le comportement voulu, il aurait fallu faire ceci:

Person p = (Person)query.getSingleResult();
p.getRemarks(); //force le chargement du champ LAZY
p.setFirstname(firstname);
p.setLastname(lastname);
p.setVersion(p.getVersion()+1);
p.setRemarks(remarks); //ok

Une autre possibilité serait de faire appel à setRemarks avant les autres setters, mais cela ne fonctionne que s'il n'y a qu'un seul champ LAZY à mettre à jour.

J'ai exposé cela dans un post sur Stackoverflow. Il y a également une question à ce propos sur le forum EclipseLink. Je dois dire que je suis assez surpris que les développeurs ne prennent pas ce ticket au sérieux, car il me paraît tout de même majeur. A noter qu'en utilisant OpenJPA, il n'y avait aucun problème avec cette annotation.

Une seule chose à faire pour améliorer la situation: voter pour le ticket en question !