jsr338-experts@jpa-spec.java.net

[jsr338-experts] Re: proposal : _at_Entity on interfaces

From: Oliver Gierke <ogierke_at_vmware.com>
Date: Mon, 12 Mar 2012 05:08:26 -0700

+1 on Mike's statement here. My initial intention (and I think Steve's as well) was what Mike explained in his other email: aliasing access to a JPA entity through an interface for the purpose of being able to separate code and e.g. have the interfaces in one JAR and the implementation class in another one.

> The key part of what was being proposed (at least how I interpreted the
> feature, Steve can correct me if I misinterpreted) was the ability to
> "alias" an entity class. This just means that one might be able register
> an entity class in the providers entity list keyed not only by the
> concrete entity class, but also an (or more than one?) interface, so
> that when the provider encounters that interface it gets loaded/saved by
> the provider as the concrete entity class.


No additional metadata, simply metadata aliasing. I think ideas like this originate from the trend for developers to build rich domain models, follow Domain Driven Design and don't treat domain classes as pure data containers. Although one might argue this is not what the JPA spec is about I think we should make sure we don't get in the way when following this approach so that devs don't get into a "I can't do this because JPA can't deal with it" situation from a class' design perspective.

Looking at the extended proposal @Entity on an interface feels a bit weird as well, at least given the current semantics in the spec. I could imagine an @EntityAlias though with the following usage model:

%<----------------------------------
@EntityAlias
public interface Person {

}

@Entity
public class MyPerson implements Person {

}
%<----------------------------------

Not sure I favor this over explicitly listing the alias interfaces on the @Entity (e.g. @Entity(typeAlias = { Person.class }) as with the original proposal you could implement the interface with a second class without creating the conflict of two implementation classes using the interface as alias.

Mike Keith wrote:

> Having said that, if we think that aliasing is one of those things that
> could stop large companies from using JPA we might decide to close our
> eyes, hold our noses and go ahead and add some kind of support.


Could you elaborate on that? I don't quite get why this feature should stop companies from using JPA.

> @Entity(alias=Employee.class)
> public class EmployeeImpl implements Employee {
> // mappings ...
> }
>
> Where does one draw the line? Would we assume that a single alias is
> enough and that an entity would not be allowed to specify a Set? For
> example, that we would not need to support something like:
>
> @Entity(aliases={Employee.class, Worker.class}) ... or ...
> @Entity(aliasInterfaces=true)
> public class EmployeeImpl implements Employee, Worker {
> // mappings ...
> }

The latter doesn't seem to complicate things, does it? At least given the assumption there has to be a single implementation class to be selected to back the type alias, right?

Cheers,
Ollie

Am 12.03.2012 um 12:37 schrieb michael keith:

> I would really prefer we not go down this path...
>
> -Mike
>
> On 12/03/2012 1:31 AM, Matthew Adams wrote:
>> If we choose to take this on, we could let users express simply
>> through simple java "implements" statements which persistent
>> interfaces a given class implements, and we could allow persistent
>> fields of persistent interface types and persistent collections of
>> interfaces types, as well as queries through them.
>>
>> @Entity
>> // or @MappedSuperclass?
>> // or new @EntityInterface?
>> public interface Employee {
>>
>> // default mapping info allowed here?
>> String getEmployeeNumber();
>> }
>> =====
>> @Entity
>> public class Person
>> implements Employee { /* no addl metadata needed -- implements is
>> sufficient */
>>
>> private String employeeNumber;
>>
>> @Column(name="emp_num")
>> public String getEmployeeNumber() { return employeeNumber; }
>> public String setEmployeeNumber(@NotNull String employeeNumber) {
>> this.employeeNumber = employeeNumber; }
>> }
>> ====
>> @Entity
>> public class Corporation {
>>
>> @OneToMany
>> @AllowedClasses({Person.class, Contractor.class})
>> private List<Employee> employees;
>>
>> @OneToOne
>> @AllowedClasses(Person.class)
>> private Employee president;
>>
>> /* Note:
>> Any assignment of a class other than those whitelisted in
>> @AllowedClasses would
>> cause the JPA implementation to throw ClassCastException
>> */
>> }
>> /*
>> @AllowedClasses could also be an attribute of relationship annotations
>> instead of its own annotation.
>> */
>> =====
>>
>> The hard part, IMHO, is portably mapping them. Wherever you have a
>> reference to a persistent interface, you also need at the point the
>> class of the implementation. Further, I would say that persistent
>> interfaces could only be mapped using property access, as interfaces
>> have no instance fields.
>>
>> One possibility is to allow the use of persistent interfaces, but just
>> say that their mappings are not portable. It would be a nontrivial
>> body of work to bite off the additional specification of portably
>> mapping persistent interfaces.
>>
>> -matthew
>>
>> On Sun, Mar 11, 2012 at 12:27 PM, michael keith
>> <michael.keith_at_oracle.com> wrote:
>>> Let me first say that I don't like the model of interfaces on entities. It
>>> is quite rarely requested and when it is, often the user wants multiple
>>> entities to be able to implement the same interface (e.g. polymorphism w/o
>>> inheritance) to do something like this:
>>>
>>> public interface Employee { ... }
>>> @Entity public class BusEmployee implements Employee { ... }
>>> @Entity public class TrainEmployee implements Employee { ... }
>>>
>>> and then in some entity:
>>>
>>> @Entity public class TranportationBureau {
>>> ...
>>> @ManyToOne
>>> Employee empOfTheMonth;
>>> }
>>>
>>> The feature being proposed, if I understood it correctly, would not support
>>> this.
>>>
>>> Having said that, if we think that aliasing is one of those things that
>>> could stop large companies from using JPA we might decide to close our eyes,
>>> hold our noses and go ahead and add some kind of support.
>>>
>>> While I understood and sympathized with the reasons why Steve first
>>> suggested that the annotation be on the interface (to facilitate
>>> interface-to-single-entity enforcement) I tend to agree with Oliver and
>>> Bernd that it would make more sense to just add an "alias" element to the
>>> @Entity annotation and continue to apply it to the impl class. It would be
>>> the responsibility of the provider to disallow two entities from creating an
>>> alias to the same class.
>>>
>>> Example:
>>>
>>> @Entity(alias=Employee.class)
>>> public class EmployeeImpl implements Employee {
>>> // mappings ...
>>> }
>>>
>>> Where does one draw the line? Would we assume that a single alias is enough
>>> and that an entity would not be allowed to specify a Set? For example, that
>>> we would not need to support something like:
>>>
>>> @Entity(aliases={Employee.class, Worker.class}) ... or ...
>>> @Entity(aliasInterfaces=true)
>>> public class EmployeeImpl implements Employee, Worker {
>>> // mappings ...
>>> }
>>>
>>> -Mike
>>>
>>>
>>> On 11/03/2012 12:23 PM, Bernd Müller wrote:
>>>> I think, this would make many things more complex to specify in a
>>>> consistent way.
>>>>
>>>> In general, interfaces are a way to describe contracts in an
>>>> implementation independent way and therefore should be as abstract
>>>> as possible. JPA is a mapping between VM-objects and databases and
>>>> therefore as close as possible to the implementation level.
>>>> Here I see some problems from a conceptual point of view.
>>>>
>>>> I also see many problems in practice. How to map fields in classes,
>>>> which are eventually named different than the annotated getter in the
>>>> interface? How to map interface hierarchies with multiple super
>>>> interfaces to eventually DIFFERENT class hierarchies with
>>>> single inheritance? There are more, I think.
>>>>
>>>> We have to balance if it's worth to get such new problems which have to
>>>> be resolved in the spec and on the other hand the benefit is less
>>>> typing (how much?).
>>>>
>>>>
>>>> Bernd
>>>>
>>>>
>>>> Am 09.03.2012 19:04, schrieb Steve Ebersole:
>>>>> I'd like to propose that JPA 2.1 allow @Entity on Java interfaces not
>>>>> just classes. The main reason is typing in spec contracts. For domain
>>>>> models that leverage interfaces, it is usually desirable to deal with
>>>>> the interfaces over the implementation classes. For example, such
>>>>> applications would generally prefer to attempt to load or get a
>>>>> reference to an instance based on the interface name as opposed to the
>>>>> class name. E.g.
>>>>>
>>>>> public interface Person {
>>>>> ...
>>>>> }
>>>>>
>>>>> @Entity
>>>>> public class PersonImpl implements Person {
>>>>> ...
>>>>> }
>>>>>
>>>>> EntityManager em = ...;
>>>>> Person p = em.find( Person.class, theKey );
>>>>>
>>>>> But this does not work today in a portable manner. To work in the most
>>>>> portable manner, I think the @Entity annotated interface also would need
>>>>> to name the "persistent implementation class":
>>>>>
>>>>> @Entity( impl = PersonImpl.class )
>>>>> public interface Person {
>>>>> ...
>>>>> }
>>>>>
>>>>> public class PersonImpl implements Person {
>>>>> ...
>>>>> }
>>>>>
>>>>> It could be up to each provider whether or not to support @Entity on an
>>>>> interface that did not specify a "persistent implementation class".
>>>>>
>>>>> Another way to look at this is as basically "aliasing" the entity type
>>>>> metadata using the interface name instead of the implementation class
>>>>> name.
>>>>>
>>>>> -Steve
>>>>
>>>>
>>
>>

-- 
/**
 * @author Oliver Gierke - Senior Member Technical Staff
 *
 * @param email ogierke_at_vmware.com
 * @param phone +49-351-30929001
 * @param fax   +49-351-418898439
 * @param skype einsdreizehn
 * @see http://www.olivergierke.de
 */