/* * Hibernate OGM, Domain model persistence for NoSQL datastores * * License: GNU Lesser General Public License (LGPL), version 2.1 or later * See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>. */ package org.hibernate.ogm.type.descriptor.impl; import javax.persistence.AttributeConverter; import javax.persistence.PersistenceException; import org.hibernate.ogm.model.spi.Tuple; import org.hibernate.ogm.type.spi.GridType; import org.hibernate.ogm.util.impl.Log; import org.hibernate.ogm.util.impl.LoggerFactory; import org.hibernate.type.descriptor.java.JavaTypeDescriptor; /** * Modeled after {@link org.hibernate.type.descriptor.converter.AttributeConverterSqlTypeDescriptorAdapter} * Adapter for incorporating JPA {@link AttributeConverter} handling into the GridTypeDescriptor contract. * * @author Emmanuel Bernard emmanuel@hibernate.org */ public class AttributeConverterGridTypeDescriptorAdaptor implements GridTypeDescriptor { private static final Log log = LoggerFactory.make(); private final AttributeConverter converter; private final GridTypeToGridTypeDescriptorAdapter delegate; private final JavaTypeDescriptor intermediateJavaTypeDescriptor; public AttributeConverterGridTypeDescriptorAdaptor( AttributeConverter converter, GridType delegate, JavaTypeDescriptor intermediateJavaTypeDescriptor) { this.converter = converter; // take the intermediary type gridType and transform it into a GridTypeDescriptor this.delegate = new GridTypeToGridTypeDescriptorAdapter( delegate ); this.intermediateJavaTypeDescriptor = intermediateJavaTypeDescriptor; } public GridType unwrapTargetGridType() { return delegate.gridType; } @Override @SuppressWarnings("unchecked") public <X> GridValueBinder<X> getBinder(JavaTypeDescriptor<X> javaTypeDescriptor) { // Get the binder for the intermediate type representation final GridValueBinder realBinder = delegate.getBinder( intermediateJavaTypeDescriptor ); return new GridValueBinder<X>() { @Override public void bind(Tuple resultset, X value, String[] names) { final Object convertedValue; try { convertedValue = converter.convertToDatabaseColumn( value ); } catch (PersistenceException pe) { throw pe; } catch (RuntimeException re) { throw new PersistenceException( "Error attempting to apply AttributeConverter", re ); } log.debugf( "Converted value on binding : %s -> %s", value, convertedValue ); try { realBinder.bind( resultset, convertedValue, names ); } catch ( Exception e ) { throw log.failureWhenUsingAttributeConverter( converter.getClass(), e ); } } }; } @Override public <X> GridValueExtractor<X> getExtractor(JavaTypeDescriptor<X> javaTypeDescriptor) { // Get the extractor for the intermediate type representation final GridValueExtractor realExtractor = delegate.getExtractor( intermediateJavaTypeDescriptor ); return new GridValueExtractor<X>() { @Override public X extract(Tuple resultset, String name) { return doConversion( realExtractor.extract( resultset, name ) ); } @SuppressWarnings("unchecked") private X doConversion(Object extractedValue) { try { X convertedValue = (X) converter.convertToEntityAttribute( extractedValue ); log.debugf( "Converted value on extraction: %s -> %s", extractedValue, convertedValue ); return convertedValue; } catch (PersistenceException pe) { throw pe; } catch (RuntimeException re) { throw log.failureWhenUsingAttributeConverter( converter.getClass(), re ); } } }; } /** * Converts GridTypeDescriptor calls to GridType calls. * <p> * That's a bit cyclic as usually GridType do use GridTypeDescriptor but they don't *have to* * and there is no way to extract the GridTypeDescriptor out of a GridType. * So we call the GridType API that usually delegates to the GridTypeDescriptor. */ private static class GridTypeToGridTypeDescriptorAdapter implements GridTypeDescriptor { private final GridType gridType; public GridTypeToGridTypeDescriptorAdapter(GridType gridType) { this.gridType = gridType; } @Override public <X> GridValueBinder<X> getBinder(JavaTypeDescriptor<X> javaTypeDescriptor) { return new GridValueBinder<X>() { @Override public void bind(Tuple resultset, X value, String[] names) { // We don't have the session, but it is usually never used // we could clean that up with a new GridType contract later gridType.nullSafeSet( resultset, value, names, null ); } }; } @Override public <X> GridValueExtractor<X> getExtractor(JavaTypeDescriptor<X> javaTypeDescriptor) { return new GridValueExtractor<X>() { @Override @SuppressWarnings( "unchecked" ) public X extract(Tuple resultset, String name) { // session and owner are usually ignored, so passing null // we could clean that up with a new GridType contract later return (X) gridType.nullSafeGet( resultset, name, null, null ); } }; } } }