users@jpa-spec.java.net

[jpa-spec users] [jsr338-experts] Re: mapping conversion

From: michael keith <michael.keith_at_oracle.com>
Date: Mon, 16 Jan 2012 16:31:46 -0500

I am fine with annotating the converter class instead of adding the
@Converter annotation to the entity class, although I don't see that
there are too many use cases for needing to define the target
convertable class name. The type parameter of the converter will define
the one that it is intended to convert, and for the most part will be
enough. Two cases that I can think of that *might* warrant an additional
type parameter are:
a) You want to map both the primitive and wrapper types (e.g. boolean
and Boolean). Not sure how often this would occur in practice.
b) You want to convert a class and all its subclasses. A subclass might
actually have additional state, though, so the conversion might not be
sufficient.

I don't believe (a) is all that useful, really. It is probably
reasonable for people to either add another converter for the primitive
type or put a @Convert annotation on it.

Similarly for (b), an empty converter subclass could be added to handle
each convertible type subclass.

I was also thinking that string names for the converters are shorter but
less typesafe than just using the class name of the converter.

Example:

@Converter
public class BooleanToIntegerConverter implements
AttributeConverter<Boolean, Integer> { ... }
@Converter(autoApply=true)
public class EmployeeDateConverter implements
AttributeConverter<com.acme.EmployeeDate, java.sql.Date> { ... }

@Entity
public class Employee {
    @Id long id;
    @Convert(com.acme.BooleanToInteger.class)
    boolean fullTime;
    ...
     // Automatically applied
    EmployeeDate startDate;
}

On 16/01/2012 12:05 AM, Bernd Müller wrote:
> Hi,
>
> I would advocate for Lindas proposal, giving some additional
> unique/global/local arguments
>
> Am 12.01.2012 01:49, schrieb Linda DeMichiel:
>> Are there any additional comments on this proposal?
>>
>> If so, please post them now.
>>
>> If not, I will proceed to add this to the spec.
>>
>> thanks,
>>
>> -Linda
>>
> I see a problem: the name of the converter is unique in the pu but
> the usage mimics locality for an entity.
>
> In JSF there is also a converter annotation called FacesConverter
> doing similar things. However it is used to annotate the converter (as
> the name implies ?)
>
> The refactored example:
>
> @Converter("booleanToInteger")
> public class BooleanToIntegerConverter implements
> ...
> }
>
> @Entity
> public class Employee {
> @Id long id;
> @Convert("booleanToInteger")
> boolean fullTime;
> ...
> }
>
> The Converter annotation uses "value" instead of "name" and is therefore
> a little bit less verbose.
> And the usage of "booleanToInteger" reflects its uniqueness instead
> of doubling the string literal in one single entity class.
>
> To demand for global application of the converter there is a second
> attribute "forClass" in @Converter defining the Class to apply for.
>
> Example
>
> @Converter(forClass=SomeBusinessPropertyType.class)
> public class ConverterForSomeBusinessPropertyType {
> ...
> }
>
> @Entity
> public class Employee {
> ...
> SomeBusinessPropertyType sbpt; // Converter applied automatically
> ...
> }
>
>
> regards
>
> Bernd
>
>
>>>> |A converter is defined using a javax.persistence.Converter
>>>> annotation. It is similar to a TableGenerator and
>>>> SequenceGenerator in that it can be defined on any entity class,
>>>> mapped superclass, or entity attribute, and given a
>>>> name, but the name must be unique within the scope of the persistence
>>>> unit.
>>>>
>>>> The annotation to use on the attribute is defined as:
>>>>
>>>> |_at_Target({TYPE, METHOD, FIELD})
>>>> @Retention(RUNTIME)
>>>> public @interface Converter {
>>>> String name();
>>>> Class converterClass();
>>>> }
>>>> |
>>>> In order to make use of a converter the @Convert annotation is used
>>>> on an entity or mapped superclass attribute. The
>>>> @Convert annotation is defined as:
>>>>
>>>> |_at_Target({METHOD, FIELD})
>>>> @Retention(RUNTIME)
>>>> public @interface Convert {
>>>> String value();
>>>> }
>>>> |
>>>> It annotates an entity attribute and specifies the name of the
>>>> converter. The same converter can be referenced by any
>>>> number of @Convert annotated attributes.
>>>> Example:
>>>>
>>>> |_at_Entity
>>>> @Converter(name="booleanToInteger",
>>>> converterClass=BooleanToIntegerConverter.class)
>>>> public class Employee {
>>>> @Id long id;
>>>> @Convert("booleanToInteger")
>>>> boolean fullTime;
>>>> ...
>>>> }||
>>>> |
>>>> |public class BooleanToIntegerConverter implements
>>>> EntityAttributeConverter<Boolean,Integer> {
>>>> public Integer convertToDatabaseColumn (Boolean attributeObject) {
>>>> return (attributeObject ? 1 : 0);
>>>> }
>>>> public Boolean convertToEntityAttribute (Integer dbData) {
>>>> return (dbData> 0)
>>>> }
>>>> }
>>>>