persistence@glassfish.java.net

Re: Possible to map boolean property to "Y" and "N" values in database?

From: Jon Miller <jemiller_at_uchicago.edu>
Date: Fri, 23 Feb 2007 13:59:02 -0600

Thanks Adam.

Jon

----- Original Message -----
From: "Adam Leftik" <adam.leftik_at_oracle.com>
To: <persistence_at_glassfish.dev.java.net>; <jemiller_at_uchicago.edu>
Sent: Friday, February 23, 2007 1:35 PM
Subject: RE: Possible to map boolean property to "Y" and "N" values in
database?


> It is possible to use do this with custom TLE converters. For a project I
> have used the following pattern to make this consistent with annotation
> based mappings to solve several direct to field mappings that do not line
> up with the default converters. The package names/comment have been
> removed to protect the innocent :)
>
> Here is a sample converter that is similar to your problem:
>
> import java.util.Vector;
>
> import oracle.toplink.essentials.descriptors.ClassDescriptor;
> import oracle.toplink.essentials.mappings.DatabaseMapping;
> import oracle.toplink.essentials.mappings.converters.Converter;
> import oracle.toplink.essentials.sessions.Session;
> import
> oracle.toplink.essentials.tools.sessionconfiguration.DescriptorCustomizer;
>
> public class BooleanConverter implements Converter {
>
>
> private static final String FALSE = "f";
> private static final String TRUE = "t";
>
> public Object convertObjectValueToDataValue(Object objectValue, Session
> session) {
> if (objectValue != null) {
> Boolean boolValue = (Boolean) objectValue;
> if (boolValue) {
> return TRUE;
> } else {
> return FALSE;
> }
> }
>
> return null;
> }
>
> public Object convertDataValueToObjectValue(Object dataValue, Session
> session) {
> if (dataValue != null) {
> String torf = dataValue.toString();
> if (TRUE.equalsIgnoreCase(torf)) {
> return Boolean.TRUE;
> } else {
> return Boolean.FALSE;
> }
> }
> return null;
> }
>
> public boolean isMutable() {
> return false;
> }
>
> public void initialize(DatabaseMapping mapping, Session session) {
> //do nothing...
>
> }
>
> }
>
> ------
> Now I want to be able to use these 'converters' with annotations so the
> following classes help make this happen. I can extend the converters
> easily by adding them to the ConverterType Enum and implementing the
> converter. The Converter annotation then can be easily used to add
> converters to any entity attribute
>
> import java.lang.annotation.Annotation;
> import java.lang.reflect.Field;
> import java.lang.reflect.Method;
> import java.util.List;
> import java.util.Map;
> import java.util.Vector;
>
>
>
> import oracle.toplink.essentials.descriptors.ClassDescriptor;
> import oracle.toplink.essentials.mappings.AggregateMapping;
> import oracle.toplink.essentials.mappings.AggregateObjectMapping;
> import oracle.toplink.essentials.mappings.DatabaseMapping;
> import oracle.toplink.essentials.mappings.DirectToFieldMapping;
>
> public class DescriptorCustomizer implements
> oracle.toplink.essentials.tools.sessionconfiguration.DescriptorCustomizer{
> public DescriptorCustomizer(){}
>
> public void customize(ClassDescriptor desc) throws Exception {
> List<DatabaseMapping> mappings = desc.getMappings();
> for (DatabaseMapping mapping : mappings) {
> if (mapping instanceof DirectToFieldMapping) {
> DirectToFieldMapping directMapping = (DirectToFieldMapping)mapping;
> String attributeName = mapping.getAttributeName();
> Class mappedClazz = mapping.getDescriptor().getJavaClass();
> checkFields(directMapping, attributeName, mappedClazz);
> checkMethods(directMapping, attributeName, mappedClazz);
> }
> }
>
> }
>
>
> private void checkMethods(DirectToFieldMapping mapping, String
> attributeName, Class clazz) throws InstantiationException,
> IllegalAccessException {
> Method [] methods = clazz.getDeclaredMethods();
> for (Method method: methods) {
> if (method.getName().equals(mapping.getGetMethodName()) ||
> method.getName().equals(mapping.getSetMethodName())) {
> Annotation [] annons = method.getAnnotations();
> checkAnnonations(mapping,annons);
> }
> }
>
> }
>
> private void checkFields(DirectToFieldMapping directMapping, String
> attributeName, Class clazz) throws InstantiationException,
> IllegalAccessException {
> Field [] fields = clazz.getDeclaredFields();
> for (Field field: fields) {
> if (field.getName().equals(attributeName)) {
> Annotation [] annotations = field.getAnnotations();
> checkAnnonations(directMapping, annotations);
> }
> }
> }
>
> private void checkAnnonations(DirectToFieldMapping directMapping,
> Annotation[] annotations) throws InstantiationException,
> IllegalAccessException {
> for (Annotation annon: annotations) {
> if (annon.annotationType().equals(Converter.class)) {
> Converter convAnnon = (Converter) annon;
> ConverterType type = convAnnon.type();
> Class converterClass = type.getConverter();
> directMapping.setConverter((oracle.toplink.essentials.mappings.converters.Converter
> )converterClass.newInstance());
> }
> }
> }
>
> }
>
>
>
> import static java.lang.annotation.ElementType.FIELD;
> import static java.lang.annotation.ElementType.METHOD;
>
> import java.lang.annotation.Retention;
> import java.lang.annotation.RetentionPolicy;
> import java.lang.annotation.Target;
>
>
>
>
> @Retention(RetentionPolicy.RUNTIME)
> @Target({FIELD, METHOD})
> public @interface Converter {
> ConverterType type();
> }
>
> ----
>
> /**
> * Converter Enumeration for converter annotations...
> */
> public enum ConverterType {
> BOOLEAN_CONVERTER (BooleanConverter.class),
> TIMEZONE_CONVERTER(TimeZoneConverter.class),
> TIMESTAMPTZ_CONVERTER(TimestampWithTZConverter.class);
>
> private Class clazz;
>
> ConverterType(Class clazz) {
> this.clazz = clazz;
> }
> public Class getConverter() {
> return clazz;
> }
> }
>
> Now here is a simple usage of this technique:
> @Entity
> public class Foo {
> @Column(name = "CUSTOMERIND")
> @Converter(type = ConverterType.BOOLEAN_CONVERTER)
> private boolean customerFlag = true;
>
> @Column(name = "TIMEZONE")
> @Converter(type = ConverterType.TIMEZONE_CONVERTER)
> private TimeZone timeZone;
>
> ....
> }
>
> Now in your persistence.xml all you need to do is add your custom
> converter! It is the same for all your converter types and you can support
> many converters per entity and the annotation makes it clear how the
> attribute is being converted. This code only works for direct to field
> mappings as it is implemented here, however, it could be extended.
>
> <persistence ...>
> <peristence-unit>
> <class>Foo</class>
> ...
> <properties>
> ...
> <!-- the pattern for name is toplink.descriptor.customizer.EntityName
> value is classname that implements the descriptor customizer interface -->
> <property name="toplink.descriptor.customizer.Foo"
> value="fullyqualnamedtoDecriptorCustomizer"/>
> </properties>
> </peristence-unit>
> </persistence>
>
>
> Hope that helps.
> -----Original Message-----
> From: Jon Miller [mailto:jemiller_at_uchicago.edu]
> Sent: Friday, Feruary 23, 2007 10:38 AM
> To: Glassfish Persistence List
> Subject: Possible to map boolean property to "Y" and "N" values in
> database?
>
>
> Hi all,
>
> This is similar to a question I had regarding enums. I'm wondering if it's
> possible to map a boolean value to "Y"s and "N"s in the database? I'm
> guessing the answer is no, but, I figured I would ask just to make sure.
>
> Jon
>