1

I have an entity with default values and a calculated field as follow:

public class Target{
    @Transient
    public Long       total;

    @Min(0)
    @Column(columnDefinition="default 0")
    public Long       val1 = 0L;
    @Min(0)
    @Column(columnDefinition="default 0")
    public Long       val2 = 0L;

    public Target() {
        this.total = Long.valueOf(0L);
        this.val1 = Long.valueOf(0L);
        this.val2 = Long.valueOf(0L);
    }

    public Long calcTotal() {
        return val1 + val2 ;
    }

    public void setVal1(Long val) {
        this.val1 = checkNotNull(val);
        total = calcTotal();
    }

    public void setVal2(Long val) {
        this.val2 = checkNotNull(val);
        total = calcTotal();
    }
}

However whenever the entity is loaded by JPA, the setters are called and a NullPointerException is thrown in calc. Is there anyway to default the values before JPA calls the setters?

1 Answer 1

5

First of all, given your mapping, the JPA engine should not call the setters at all, because you chose field access by placing the annotations on the field.

Second, there is no total field in the code.

Third, this field should not exist at all, since it can be computed from two other fields. Just let other classes call calcTotal() to access its value. And rename this method getTotal().

Oh, and the fields should be private, not public.

If you really want to store the result for reuse, then compute it lazily, and reset it to null when one of the operands is modified:

public Long getTotal() {
    if (total == null) {
        total = val1 + val2;
    }
    return total;
}

public void setVal1(Long val1) {
    this.val1 = val1;
    this.total = null;
}

public void setVal2(Long val2) {
    this.val2 = val2;
    this.total = null;
}
Sign up to request clarification or add additional context in comments.

5 Comments

I've edited the code with the missing field total. I believe play framework enhances JPA and adds getter/setters if those are not present. The fields need to be public though. The idea is to only compute total whenever one of the value is updated and not every time the total is required.
Unless Play completely changes the code of the entity, my points still remain: the setters shouldn't be accessed in the first place. And the way you've mapped total, it's persisted in database, which is not necessary at all. And the cost of the addition is ridiculous and negligible compared to the cost of loading the entity from the database. Computing it at each access won't make any significant difference.
Good point about the persistence of the total, I will make it transient. However this is a simplified example and in my particular case this make sense.
Then return the value of total if not null when getTotal() is called, compute it and store its result in total when getTotal() is called if total is null, and reset total to null each time a setter on one of the operands is called. See my updated answer.
I'll accept the answer as I can work around the problem. However I am still not sure why the fields are not initialised before the setters are called. I guess I need to dig into Play's magic tricks.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.