/*
* Copyright (c) 2005-2016 Vincent Vandenschrick. All rights reserved.
*
* This file is part of the Jspresso framework.
*
* Jspresso is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Jspresso is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Jspresso. If not, see <http://www.gnu.org/licenses/>.
*/
package org.jspresso.framework.model.persistence.hibernate.property;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.util.Map;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.property.Getter;
import org.hibernate.property.PropertyAccessor;
import org.hibernate.property.Setter;
import org.jspresso.framework.model.component.IComponent;
import org.jspresso.framework.util.bean.PropertyHelper;
/**
* This class the contract defined by hibernate to enable entity properties to
* be accessed. Since entities are generically implemented by a proxy, the
* strategy used by hibernate can't be "field" based. We could have used the
* "property strategy, but each and every time hibernate would have mutated the
* properties to refresh them based on the backing store, the business rules and
* integrity rules would have been fired. It is none-sense in terms of
* performance and even in terms of functionality since we know that the values
* held in the backing store are considered to have been checked formerly.
* Considering the previous points, this implementation uses a intermediate
* strategy which update the property values without firing anything but a
* {@code PropertyChangeEvent} in case the actual property value changed.
*
* @author Vincent Vandenschrick
*/
@SuppressWarnings("rawtypes")
public class EntityPropertyAccessor implements PropertyAccessor {
/**
* {@inheritDoc}
*/
@Override
public Getter getGetter(Class theClass, String propertyName) {
return new EntityPropertyGetter(theClass, propertyName);
}
/**
* {@inheritDoc}
*/
@Override
public Setter getSetter(Class theClass, String propertyName) {
return new EntityPropertySetter(theClass, propertyName);
}
/**
* Implements the getter strategy on the entity proxy implementation to be
* used by hibernate.
*
* @author Vincent Vandenschrick
*/
private static final class EntityPropertyGetter implements Getter {
private static final long serialVersionUID = -7896937881971754040L;
private final Class<?> propertyClass;
private final String propertyName;
private final Method getter;
/**
* Constructs a new {@code EntityPropertyGetter} instance.
*
* @param theClass
* The class of the entity.
* @param propertyName
* the name of the property to access.
*/
public EntityPropertyGetter(Class<?> theClass, String propertyName) {
this.propertyName = PropertyHelper
.fromJavaBeanPropertyName(propertyName);
this.propertyClass = PropertyHelper.getPropertyType(theClass,
propertyName);
this.getter = PropertyHelper
.getPropertyDescriptor(theClass, propertyName).getReadMethod();
}
/**
* {@inheritDoc}
*/
@Override
public Object get(Object target) {
return ((IComponent) target).straightGetProperty(propertyName);
}
/**
* {@inheritDoc}
*/
@Override
public Object getForInsert(Object target, Map mergeMap,
SessionImplementor session) {
return get(target);
}
/**
* Actually returns the getter method.
* <p>
* {@inheritDoc}
*/
@Override
public Method getMethod() {
return getter;
}
/**
* Actually returns getter method name.
* <p>
* {@inheritDoc}
*/
@Override
public String getMethodName() {
if (getter != null) {
return getter.getName();
}
return null;
}
/**
* {@inheritDoc}
*/
@Override
public Class<?> getReturnType() {
return propertyClass;
}
/**
* Actually returns the getter method. {@inheritDoc}
*/
@Override
public Member getMember() {
return getter;
}
}
/**
* Implements the setter strategy on the entity proxy implementation to be
* used by hibernate.
*
* @author Vincent Vandenschrick
*/
private static final class EntityPropertySetter implements Setter {
private static final long serialVersionUID = 1836686220358025728L;
private final String propertyName;
private final Method setter;
/**
* Constructs a new {@code EntityPropertySetter} instance.
*
* @param theClass
* The class of the entity.
* @param propertyName
* the name of the property to access.
*/
public EntityPropertySetter(Class<?> theClass, String propertyName) {
this.propertyName = PropertyHelper
.fromJavaBeanPropertyName(propertyName);
this.setter = PropertyHelper
.getPropertyDescriptor(theClass, propertyName).getWriteMethod();
}
/**
* Actually returns the setter.
* <p>
* {@inheritDoc}
*/
@Override
public Method getMethod() {
return setter;
}
/**
* Actually returns the setter name.
* <p>
* {@inheritDoc}
*/
@Override
public String getMethodName() {
if (setter != null) {
return setter.getName();
}
return null;
}
/**
* {@inheritDoc}
*/
@Override
public void set(Object target, Object value,
SessionFactoryImplementor factory) {
((IComponent) target).straightSetProperty(propertyName, value);
}
}
}