users@jpa-spec.java.net

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

From: Evan Ireland <eireland_at_sybase.com>
Date: Tue, 20 Dec 2011 14:15:12 +1300

Linda,

Do you have to use @Convert on every attribute to be converted?

In:

> > @Id long id;
> > @Convert("booleanToInteger")
> > boolean fullTime;

should id be 'int', not 'long'?

I'm on vacation so probably won't read any reply until next month :-)

> -----Original Message-----
> From: Linda DeMichiel [mailto:linda.demichiel_at_oracle.com]
> Sent: Tuesday, 20 December 2011 10:22 a.m.
> To: jsr338-experts_at_jpa-spec.java.net
> Cc: michael keith
> Subject: [jsr338-experts] Re: mapping conversion
>
> Hi all,
>
> It would be good to get some feedback from you on this proposal!
>
> As I hope you might expect, I don't have any major feedback since
> Mike and I have discussed this beforehand :-) when he was kind enough
> to volunteer to drive this feature.
>
> The few suggestions I do have are embedded below. Otherwise, I
> think we should proceed to add this feature to the spec.
>
> thanks,
>
> -Linda
>
>
> On 12/9/2011 1:02 PM, michael keith wrote:
> > Hi everyone,
> >
> > One of the most common feature requests from people who are
> mapping entities using JPA is a way to transform or convert
> > the state from the way it is stored in the entity attribute
> to the way it is stored in the database, and vice versa. A
> > "converter" provides this functionality. Below is a
> proposal for converters.
> >
> > A converter is an object that implements the
> javax.persistence.mappings.EntityAttributeConverter
> interface, defined as:
> >
> > (*** OPEN ISSUE: Should the package just be
> javax.persistence or should a subpackage be used in
> anticipation of other
> > mapping extensions? Some people have asked for a mapping
> API and this class would probably fit in with that.)
> >
>
> I would keep this in javax.persistence, as it is pretty basic
> functionality.
> We can revisit later on (i.e. until JPA 2.1 PFD) if we change
> our mind.
>
> > (*** OPEN ISSUE: Is there a better classname and method pair?)
> >
>
> I would drop "Entity" from the interface name
>
> > /**
> > * A class that implements this interface can be used to
> convert entity attribute state
> > * into database column representation and back again. Note
> that the X and Y types may
> > * be the same Java type.
> > *
> > * @param X The type of the entity attribute
> > * @param Y The type of the database column
> > */
> > |public interface EntityAttributeConverter<X,Y> {||
> > /** ||
> > * Converts the object stored in the entity attribute
> into the data representation||
> > || * to be stored in the database.
> > *
> > * @param attributeObject The object in the entity
> attribute to be ||converted
> > * @return The converted data to be stored in the
> database column||
> > */||
> > public Y convertToDatabaseColumn (X attributeObject);||
> > ||
> > /** ||
> > * Converts the data stored in the database column
> into an object ||
> > * to be stored in the entity attribute.||
> > *||
> > * @param dbData The data from the database column to
> be converted||
> > * @return The converted state to be stored in the
> entity attribute||
> > */||
> > public X convertToEntityAttribute (Y dbData);||
> > }
> >
> > |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)
> > }
> > }
> >
>
> Since the converter is a class (unlike TableGenerator and
> SequenceGenerator),
> I'm thinking it would be nicer if we could apply the annotation to the
> converter class rather than to an entity, mapped superclass,
> or attribute
> in order to define the class as a converter.
>
> We could then default the name of the converter to the lowercased
> unqualified class name, or allow a name to be specified.
>
> e.g.,
>
> @Converter //name defaults to booleanToInteger
> public class BooleanToInteger implements AttributeConverter {...}
>
> or
> @Converter(name="booleanToInt")
> public class BooleanToInteger implements AttributeConverter {...}
>
>
>
> > |The Container is responsible for invoking the
> corresponding method when loading a converted entity
> attribute from the
> > database, or before saving that entity attribute state to
> the database.
> >
> > The @Convert annotation may be used on default or
> explicitly mapped basic attributes. It is not portably supported to
> > use @Convert on mappings marked with @Enumerated,
> @Temporal, @Id, @Version or on embedded, relationship or element
> > collection attributes.
> >
> > (*** OPEN ISSUE: Should we require providers to support
> some of these mappings? I can see supporting the conversion of
> > temporal and enumerated attribute types, but in those cases
> @Convert would be used on its own, not in combination with
> > either @Enumerated or @Temporal.)
> >
>
> Yes
>
> > Schema Generation
> >
> > When using schema generation a provider may choose to
> assume the column type matches the entity attribute type if no
> > additional @Column.columnDefinition is supplied, or a
> provider may have an alternate way of deciding the column type for
> > an entity attribute.
> >
> > Queries
> >
> > Instances of attribute values in JP QL or criteria queries
> (such as in comparisons or bulk assignments, etc) must be
> > converted to database types before the queries are
> executed. If the result of a query includes one or more specific
> > entity attributes then the results must be converted to
> entity attribute form before being returned.
> >
> > XML
> >
> > Converters can be defined in XML at method, class, mapping
> file or persistence unit level, similar to generators, and
> > will override the same named converters if such converters
> were defined in annotation form.
> >
>
> If we follow the suggestion above, I would do this at mapping
> file or persistence unit levels only.
>
> > Enhancements
> >
> > This proposal covers converting data from a single column
> to a single entity attribute. The assumptions are:
> >
> > a)This will cover the 90% case
> >
> > b)More advanced cases, such as multiple columns to a single
> attribute, can be covered by a more advanced mapping or a
> > more advanced converter type that can be added later if necessary
> >
> > c)It is not worth convoluting the simple case to handle a
> much less likely complex case
> >
> > Comments?
> >
> > -Mike
> >
>
>