4

I'm sure this is strongly related to this question but the op on that question has a bit of a scenario that I'm not sure even makes sense for DI. So here's what I understand, it's generally not a good idea to try to mix a JPA Entity with a CDI Bean because both are generally done by creating proxy objects. Here's what I envisioned, but from what I've read this is not possible.

@Entity
public class MyUniqueObject implements Serializable {

    @Inject
    private transient Logger log;

    @Inject
    private transient Event<MyUniqueObjectEvent> events;

    @Id
    private long id;

    @NotNull
    private String text;

    public void setText( final String text ) {
       log.debug( "updating text {}", this );
       this.text = text;
       events.fire( new MyUniqueObjectEvent( this ) ); // consumed by an @Observes method
    }
}

What's the best way to do what I'm trying to accomplish? which is fundamentally things like events firing from within JPA persisted entities, access to log objects. Code examples helpful.

Community
  • 1
  • 1
xenoterracide
  • 16,274
  • 24
  • 118
  • 243
  • I can see what you're trying to do, but still looks to me that you're trying to add business logic to an entity bean, so it sounds to me like something wrong here. Instead, I'd send the entities to some business logic class that instead would observe the entities for changes maybe. (of course, you'd had to wrap the setText() to something else in the business object), or maybe you could use some AOP way to intercept the methods in your entity bean. Not sure, just some ideas. – Leo Feb 13 '14 at 02:21
  • 1
    @Leo are Entity beans not allowed to have business logic? I thought the purpose of something like Hibernate was to be able to persist business objects directly? à la [Data Mapper](http://martinfowler.com/eaaCatalog/dataMapper.html) – xenoterracide Feb 13 '14 at 02:37
  • well, I understand that entity beans have no logic, they just have data, and hibernate just deals with their persistence. Business logic, on the other side, I understand that have logic but (most of the time) transient state. But, you know, there's no golden rule. – Leo Feb 13 '14 at 02:58
  • in the end, all we have is a problem, code and a developer ;-) – Leo Feb 13 '14 at 03:00
  • The only thought I've had so far is loading the entity via hibernate and then calling protected setters to add the logger/events/etc objects. – xenoterracide Feb 13 '14 at 06:41
  • Injection is not allowed in entities and there is a reason for that. Don't mess any logic with your entities! – Adrian Mitev Feb 13 '14 at 06:53
  • you guys are suggesting [Anemic Models](http://www.martinfowler.com/bliki/AnemicDomainModel.html) if I'm understanding you right. I'm creating a rich model, which I've seen examples of persisted with hibernate (of course none of them used CDI). So I know that's not impossible. – xenoterracide Feb 13 '14 at 07:22

1 Answers1

4

I am wondering if it's really useful to observe every change to entity attributes, even if they won't eventually get persisted. So don't you think that Entity Listeners and Callbacks woudn't be sufficient for you?They support CDI since JPA 2.1 and offer plenty of callbacks which you can observe

  • @PrePersist
  • @PreRemove
  • @PostPersist
  • @PostRemove
  • @PreUpdate
  • @PostUpdate
  • @PostLoad

So you will get

@EntityListeners(class=Audit.class)
@Entity
public class MyUniqueObject implements Serializable {}


public class Audit {

    @Inject
    private Logger log;

    @Inject
    private Event<MyUniqueObjectEvent> events;

}

Now you can observe the lifecycle of your entity - also it's better that you have separated your model and its auditing, you don't have to mess up with setters and getters (which is confusing) to achieve logging. Also note that you can also define Default Entity Listeners for every entity you have.

Petr Mensik
  • 26,874
  • 17
  • 90
  • 115
  • is it possible to use this when you're not persisting via JPA? e.g. some of my tests. – xenoterracide Feb 13 '14 at 21:10
  • I am not sure but I think that Callbacks will be tied to JPA so you won't get any auditing during tests. But I am not sure why would you want that - usually you need to test if you can persist the entity, if the primary key is generated or not and so on, testing getters or setters doesn't serve any purpose. – Petr Mensik Feb 13 '14 at 21:24
  • because my example was designed to be simplistic, rather than provide every single case I might run into... – xenoterracide Feb 13 '14 at 21:55
  • Sure, but like I said, it's not a very good idea to combine model and logic, these two things should simply be separated. – Petr Mensik Feb 13 '14 at 22:04
  • for future people, I decided to write a factory, that has a method called by the factors create function, that method is also annotated by @PostLoad, so hibernate can call it. – xenoterracide Feb 17 '14 at 21:48