1

I have a JPA Project (Eclipse Link), works fine but I want to persist a class that is not Entity(Or Not entity in the same Persistence Context), currently I persist the reference id, and after that I do the call to retrieve the Object. I need know what is the best way to do that.. I do not want add code in the bean as listener event, because I want have a clean bean(constructos,properties, setters and getters without annotations),

My Idea is to extend the PersistenceContext(but, I do not know how to do it) adding a filter and identify the class to persist and doing something to replace the persistence of the class not mapped.

Any ideas or my question is out of place?

This is a Simple Example..

@Entity
public class Customer{

@Column
Integer id;

@Column
/*transient?*/
CustomerInfo customerInfo

/*setters and getters*/
}

/*this class maybe not be Entity.. Maybe be a Web Service Response Bean*/
public class CustomerInfo{
   private String firstName;
   private String lastName;
   private BigDecimal balance;
   /*setters and getters*/
}
Jens Schauder
  • 77,657
  • 34
  • 181
  • 348
jrey
  • 2,163
  • 1
  • 32
  • 48
  • 1
    why not using an Embeddable ? It looks like what you want to do ... – NoDataFound Sep 30 '14 at 21:16
  • @NoDataFound.. but I do not want save the CustomerInfo data.. I want persist only the reference to retrieve or save the CustomerInfo with a WebService Calling. – jrey Sep 30 '14 at 21:20
  • 1
    I assume that you CustomerInfo has some kind of key allowing you to retrieve it ? That key would be a reference you would need to pass each to the WS. – NoDataFound Sep 30 '14 at 21:33
  • Yes, I have a key that I will pass to the WS.. But the WS returns more Information that I do not want to Persist. the CustomerInfo is going to have more fields on the time and is probably that this change frequently(all days). – jrey Oct 01 '14 at 14:52

3 Answers3

1

As proposed by NoDataFound in the comment, if you do not want to add an Id, an Embeddable/Embedded tandem could be the solution: because of the Id problem, you should have the data in the same table (it is possible to keep different classes). You have the doc in the Java EE tutorial. If you don't want to change the code, you could use the XML for object/relational mapping. In the wikibook about JPA you have an XML sample.

Community
  • 1
  • 1
bdulac
  • 1,686
  • 17
  • 26
  • when I say that I do not want to add code in my Bean.. I refer that I do not want add PrePersist, PostPersist, or similar annotation, etc with annotations or with XML, I want add the PostPersist event maybe On an External class, Manager, Listener. Thanks! – jrey Oct 01 '14 at 14:56
1

Following my comments: create an embeddable CustomerInfoKey with the essential information.

Two solutions then:

  1. Inheritance:

    • Have CustomerInfo inherits CustomerInfoKey
    • Use setCustomerInfoKey(customerInfo) with customerInfo a CustomerInfo.
  2. Composition and delegation:

    • Have a field CustomerInfoKey key in CustomerInfo
    • Delegate the getter/setter of CustomerInfoKey in CustomerInfo:

      public Foobar getFoobar() {return key.getFoobar()}
      public void setFoobar(Foobar foobar) {key.setFoobar(key);}
      
    • Have a method getKey() and use it to persist data; you can even create a setter taking a CustomerInfo in Customer and doing the appropriate stuff.

I don't know how JPA implementations behave when it encounters partial mapping like solution #1. But it should work.

NoDataFound
  • 11,381
  • 33
  • 59
  • Looks well.. but I do not understand, I do not see. how could setting the another properties retrieved from WS call in the CustomerInfo. The properties I need to add after call all findById Or query.. – jrey Oct 01 '14 at 18:43
  • Could you clarify your question with examples: do you want to do some lazy loading like `customer.getCustomerInfo()` instead of something like `customerInfoService.findById(customer.getCustomerKey())` ? Also explain if you use Spring, CDI, etc because you'll still need to inject/get a `customerInfoService` to do the work. – NoDataFound Oct 01 '14 at 20:05
  • Hi NoDataFound, you gave me the Idea to resolve, I Share the solution If you Can Check if you think that is a Good Way.. – jrey Oct 04 '14 at 16:25
0

To resolve this, I am creating a EntityListener:

public interface JREntityListener<T> {
    public Class getTarget();
    public void postUpdate(T t) throws Exception;
    public void postCreate(T t) throws Exception;
    public void preMerge(T t) throws Exception;
    public void postMerge(T t) throws Exception;
    public void prePersist(T t) throws Exception;
    public void postPersist(T t) throws Exception;
}

I am Created a Class to Catch the events of a Entity

public class JRDescriptorEventListener<T> implements DescriptorEventListener{
  //implements all methods of DescriptorEventListener
  //i am Show only One to Example
  @Override
  public void postClone(DescriptorEvent descriptorEvent) {
    //        descriptorEvent.getObject();
    try {
      logger.info("postClone");
      t.postUpdate((T) descriptorEvent.getObject());
    } catch (Exception e) {
      throw new RuntimeException(e);
    }
  }   
}

I am created a Binding EntityListener with PersistenceContext (Thanks jhadley by injecting a spring dependency into a JPA EntityListener):

public void addListener(JREntityListener t) {
    JpaEntityManager entityManager = null;
    try {
        // Create an entity manager for use in this function
        entityManager = (JpaEntityManager) entityManagerFactory.createEntityManager();
        // Use the entity manager to get a ClassDescriptor for the Entity class
        ClassDescriptor desc =
                entityManager.getSession().getClassDescriptor(t.getTarget());
        JRDescriptorEventListener jrDescriptorEventListener = new JRDescriptorEventListener(t);
        desc.getEventManager().addListener(jrDescriptorEventListener);
        logger.info("Entity Listener for " + t.getTarget().getCanonicalName() + " is added");
    } catch (Exception e) {
        logger.error(e.getMessage(), e);
    } finally {
        if (entityManager != null) {
            // Cleanup the entity manager
            entityManager.close();
        }
    }
}

Now I am implements the Listener addind Listener

javoraiPersistenceBase.addListener(myEntityListener);

public class MyEntityListener implements JavoraiEntityListener<Customer> {

     @Autowired
     CustomerSvc customerSvc;


     @Override
     public Class getTarget() {
         return Customer.class;
     }

     @Override
    public void postUpdate(Customer customer) throws Exception {
      CustomerInfo customerInfo = globalDataSvc.findCustomerInfoById(customer.getCustomerInfo().getId());
      customer.setCustomerInfo(customerInfo);
    }
}
Community
  • 1
  • 1
jrey
  • 2,163
  • 1
  • 32
  • 48
  • I won't say it's bad or good, but I'm pretty much against dependency injection in an entity. It think it makes it too complicated for the advantages it brings (also, I quite don't understand your real need, perhaps I would simply called a dedicated service for that when I need it, instead of doing implicitly [or unobviously], without even knowing if it would be useful). – NoDataFound Oct 04 '14 at 18:33
  • EntityListener is not an Entity, I add the customerSvc for complete the additional info of CustomerInfo, but Maybe is some complicated. – jrey Oct 04 '14 at 20:27