HHH-3000 Allow a TypeDef to be associated with a class (Sharath Reddy)

git-svn-id: https://svn.jboss.org/repos/hibernate/core/trunk@17626 1b8cb986-b30d-0410-93ca-fae66ebed9b2
This commit is contained in:
Emmanuel Bernard 2009-10-06 07:50:35 +00:00
parent 460a7ace1c
commit c6a32b933d
14 changed files with 647 additions and 32 deletions

View File

@ -1,7 +1,7 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
* Copyright (c) 2009, Red Hat Middleware LLC or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC.
@ -37,9 +37,9 @@ import java.lang.annotation.Target;
@Target({TYPE, PACKAGE})
@Retention(RUNTIME)
public @interface TypeDef {
String name();
Class typeClass();
String name() default "";
Class<?> typeClass();
Class<?> defaultForType() default void.class;
Parameter[] parameters() default {};
}

View File

@ -104,7 +104,6 @@ import org.hibernate.annotations.Index;
import org.hibernate.annotations.LazyToOne;
import org.hibernate.annotations.LazyToOneOption;
import org.hibernate.annotations.ManyToAny;
import org.hibernate.annotations.MapKeyManyToMany;
import org.hibernate.annotations.NaturalId;
import org.hibernate.annotations.NotFound;
import org.hibernate.annotations.NotFoundAction;
@ -137,7 +136,6 @@ import org.hibernate.cfg.annotations.QueryBinder;
import org.hibernate.cfg.annotations.SimpleValueBinder;
import org.hibernate.cfg.annotations.TableBinder;
import org.hibernate.cfg.annotations.MapKeyColumnDelegator;
import org.hibernate.cfg.annotations.CustomizableColumns;
import org.hibernate.cfg.annotations.MapKeyJoinColumnDelegator;
import org.hibernate.engine.FilterDefinition;
import org.hibernate.engine.Versioning;
@ -1005,9 +1003,23 @@ public final class AnnotationBinder {
for (Parameter param : defAnn.parameters()) {
params.setProperty( param.name(), param.value() );
}
if (BinderHelper.isDefault(defAnn.name()) && defAnn.defaultForType().equals(void.class)) {
throw new AnnotationException("Both name and defaultForType attributes cannot be set in a TypeDef");
}
if (!BinderHelper.isDefault(defAnn.name())) {
log.info( "Binding type definition: {}", defAnn.name() );
mappings.addTypeDef( defAnn.name(), defAnn.typeClass().getName(), params );
}
else if (!defAnn.defaultForType().equals(void.class)) {
log.info( "Binding type definition: {}", defAnn.defaultForType().getName() );
mappings.addTypeDef( defAnn.defaultForType().getName(), defAnn.typeClass().getName(), params );
}
else {
throw new AnnotationException("Either name or defaultForType attribute should be set in a TypeDef");
}
}
private static void bindDiscriminatorToPersistentClass(
RootClass rootClass,
@ -1365,12 +1377,13 @@ public final class AnnotationBinder {
propBinder.setHolder( propertyHolder ); //PropertyHolderBuilder.buildPropertyHolder(rootClass)
propBinder.setProperty( property );
propBinder.setReturnedClass( inferredData.getPropertyClass() );
propBinder.setMappings( mappings );
Property prop = propBinder.bind();
propBinder.getSimpleValueBinder().setVersion(true);
rootClass.setVersion( prop );
SimpleValue simpleValue = (SimpleValue) prop.getValue();
if ( !simpleValue.isTypeSpecified() ) simpleValue.setTypeName( "integer" );
simpleValue.setNullValue( "undefined" );
rootClass.setOptimisticLockMode( Versioning.OPTIMISTIC_LOCK_VERSION );
log.debug(

View File

@ -312,8 +312,17 @@ public class AnnotationConfiguration extends Configuration {
caches.clear();
try {
inSecondPass = true;
processFkSecondPassInOrder();
Iterator iter = secondPasses.iterator();
while ( iter.hasNext() ) {
SecondPass sp = (SecondPass) iter.next();
//do the second pass of simple value types first and remove them
if ( sp instanceof SetSimpleValueTypeSecondPass ) {
sp.doSecondPass( classes );
iter.remove();
}
}
processFkSecondPassInOrder();
iter = secondPasses.iterator();
while ( iter.hasNext() ) {
SecondPass sp = (SecondPass) iter.next();
//do the second pass of fk before the others and remove them
@ -1111,6 +1120,11 @@ public class AnnotationConfiguration extends Configuration {
defaultNamedGenerators.add( generator.getName() );
}
public boolean isInSecondPass() {
return inSecondPass;
}
public IdGenerator getGenerator(String name) {
return getGenerator( name, null );
}

View File

@ -156,4 +156,7 @@ public interface ExtendedMappings extends Mappings {
public void addAnyMetaDef(AnyMetaDef defAnn) throws AnnotationException;
public AnyMetaDef getAnyMetaDef(String name);
public boolean isInSecondPass();
}

View File

@ -0,0 +1,46 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2009, Red Hat, Inc. and/or its affiliates or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program 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 this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.cfg;
import java.util.Map;
import org.hibernate.MappingException;
import org.hibernate.cfg.annotations.SimpleValueBinder;
/**
* @author Sharath Reddy
*
*/
public class SetSimpleValueTypeSecondPass implements SecondPass {
SimpleValueBinder binder;
public SetSimpleValueTypeSecondPass(SimpleValueBinder val) {
binder = val;
}
public void doSecondPass(Map persistentClasses) throws MappingException {
binder.fillSimpleValue();
}
}

View File

@ -61,6 +61,8 @@ public class PropertyBinder {
private boolean insertable = true;
private boolean updatable = true;
private String cascade;
private SimpleValueBinder simpleValueBinder;
/*
* property can be null
* prefer propertyName to property.getName() since some are overloaded
@ -133,15 +135,15 @@ public class PropertyBinder {
String containerClassName = holder == null ?
null :
holder.getClassName();
SimpleValueBinder value = new SimpleValueBinder();
value.setMappings( mappings );
value.setPropertyName( name );
value.setReturnedClassName( returnedClassName );
value.setColumns( columns );
value.setPersistentClassName( containerClassName );
value.setType( property, returnedClass );
value.setMappings( mappings );
SimpleValue propertyValue = value.make();
simpleValueBinder = new SimpleValueBinder();
simpleValueBinder.setMappings( mappings );
simpleValueBinder.setPropertyName( name );
simpleValueBinder.setReturnedClassName( returnedClassName );
simpleValueBinder.setColumns( columns );
simpleValueBinder.setPersistentClassName( containerClassName );
simpleValueBinder.setType( property, returnedClass );
simpleValueBinder.setMappings( mappings );
SimpleValue propertyValue = simpleValueBinder.make();
setValue( propertyValue );
Property prop = make();
holder.addProperty( prop, columns );
@ -214,4 +216,9 @@ public class PropertyBinder {
public void setReturnedClass(XClass returnedClass) {
this.returnedClass = returnedClass;
}
public SimpleValueBinder getSimpleValueBinder() {
return simpleValueBinder;
}
}

View File

@ -42,6 +42,7 @@ import org.hibernate.cfg.BinderHelper;
import org.hibernate.cfg.Ejb3Column;
import org.hibernate.cfg.ExtendedMappings;
import org.hibernate.cfg.NotYetImplementedException;
import org.hibernate.cfg.SetSimpleValueTypeSecondPass;
import org.hibernate.mapping.SimpleValue;
import org.hibernate.mapping.Table;
import org.hibernate.type.ByteArrayBlobType;
@ -68,6 +69,16 @@ public class SimpleValueBinder {
private Properties typeParameters = new Properties();
private ExtendedMappings mappings;
private Table table;
private SimpleValue simpleValue;
private boolean isVersion;
public boolean isVersion() {
return isVersion;
}
public void setVersion(boolean isVersion) {
this.isVersion = isVersion;
}
public void setPropertyName(String propertyName) {
this.propertyName = propertyName;
@ -238,16 +249,35 @@ public class SimpleValueBinder {
}
public SimpleValue make() {
validate();
log.debug( "building SimpleValue for {}", propertyName );
if ( table == null ) {
table = columns[0].getTable();
}
SimpleValue simpleValue = new SimpleValue( table );
return fillSimpleValue( simpleValue );
simpleValue = new SimpleValue( table );
for (Ejb3Column column : columns) {
column.linkWithValue( simpleValue );
}
public SimpleValue fillSimpleValue(SimpleValue simpleValue) {
boolean isInSecondPass = mappings.isInSecondPass();
if (!isInSecondPass) {
//Defer this to the second pass
SetSimpleValueTypeSecondPass secondPass = new SetSimpleValueTypeSecondPass(this);
mappings.addSecondPass(secondPass);
}
else {
//We are already in second pass
fillSimpleValue();
}
return simpleValue;
}
public void fillSimpleValue() {
log.debug( "setting SimpleValue typeName for {}", propertyName );
String type = BinderHelper.isDefault( explicitType ) ? returnedClassName : explicitType;
org.hibernate.mapping.TypeDef typeDef = mappings.getTypeDef( type );
if ( typeDef != null ) {
@ -262,9 +292,10 @@ public class SimpleValueBinder {
if ( persistentClassName != null ) {
simpleValue.setTypeUsingReflection( persistentClassName, propertyName );
}
for (Ejb3Column column : columns) {
column.linkWithValue( simpleValue );
if ( !simpleValue.isTypeSpecified() && isVersion()) {
simpleValue.setTypeName( "integer" );
}
return simpleValue;
}
}

View File

@ -342,6 +342,76 @@ public class BasicHibernateAnnotationsTest extends TestCase {
s.close();
}
/**
* We persist and retrieve properties of type 'PhoneNumber'. We set this type to delegate to
* the Hibernate UserType 'PhoneNumberType' for persistence and retrieval (with the 'defaultForType' attribute).
* However, we can also use the @TypeDef 'name' attribute and @Type annotation to over-ride this and
* delegate to OverseasPhoneNumberType.
*
*/
public void testTypeDefsUsingNameAndDefaultForType() {
ContactDetails contactDetails = new ContactDetails();
contactDetails.setLocalPhoneNumber(new PhoneNumber("999999"));
contactDetails.setOverseasPhoneNumber(new PhoneNumber("111111"));
Session s = openSession();
Transaction tx = s.beginTransaction();
s.persist(contactDetails);
tx.commit();
s.close();
s = openSession();
tx = s.beginTransaction();
contactDetails =
(ContactDetails) s.get( ContactDetails.class, contactDetails.getId() );
assertNotNull( contactDetails );
assertEquals( "999999", contactDetails.getLocalPhoneNumber().getNumber() );
assertEquals( "041111111", contactDetails.getOverseasPhoneNumber().getNumber() );
s.delete(contactDetails);
tx.commit();
s.close();
}
/**
* A custom type is used in the base class, but defined in the derived class.
* This would have caused an exception, because the base class is processed
* BEFORE the derived class, and the custom type is not yet defined. However,
* it works now because we are setting the typeName for SimpleValue in the second
* pass.
*
*
* @throws Exception
*/
public void testSetSimpleValueTypeNameInSecondPass() throws Exception {
Peugot derived = new Peugot();
derived.setName("sharath");
Session s;
Transaction tx;
s = openSession();
tx = s.beginTransaction();
s.persist(derived);
tx.commit();
s.close();
s = openSession();
tx = s.beginTransaction();
derived = (Peugot) s.get( Peugot.class, derived.getId() );
assertNotNull( derived );
assertEquals( "SHARATH", derived.getName() );
s.delete(derived);
tx.commit();
s.close();
}
public BasicHibernateAnnotationsTest(String x) {
super( x );
}
@ -353,7 +423,10 @@ public class BasicHibernateAnnotationsTest extends TestCase {
Ransom.class,
ZipCode.class,
Flight.class,
Name.class
Name.class,
Car.class,
Peugot.class,
ContactDetails.class
};
}

View File

@ -0,0 +1,58 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2009, Red Hat, Inc. and/or its affiliates or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program 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 this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.test.annotations.entity;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import org.hibernate.annotations.Type;
/**
* Uses a custom type which is defined in a subclass
* @author Sharath Reddy
*/
@Entity
public class Car {
@Id
@GeneratedValue
private int id;
@Type(type="definedInDerivedClass")
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}

View File

@ -0,0 +1,89 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2009, Red Hat, Inc. and/or its affiliates or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program 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 this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.test.annotations.entity;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import org.hibernate.annotations.Type;
import org.hibernate.annotations.TypeDef;
import org.hibernate.annotations.TypeDefs;
@TypeDefs(
{
@TypeDef(
name = "overseasPhoneNumber",
typeClass = OverseasPhoneNumberType.class
),
@TypeDef(
defaultForType = PhoneNumber.class,
typeClass = PhoneNumberType.class
)
}
)
/**
* @author Sharath Reddy
*
*/
@Entity
public class ContactDetails {
@Id
@GeneratedValue
private int id;
private PhoneNumber localPhoneNumber;
@Type(type="overseasPhoneNumber")
private PhoneNumber overseasPhoneNumber;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public PhoneNumber getLocalPhoneNumber() {
return localPhoneNumber;
}
public void setLocalPhoneNumber(PhoneNumber localPhoneNumber) {
this.localPhoneNumber = localPhoneNumber;
}
public PhoneNumber getOverseasPhoneNumber() {
return overseasPhoneNumber;
}
public void setOverseasPhoneNumber(PhoneNumber overseasPhoneNumber) {
this.overseasPhoneNumber = overseasPhoneNumber;
}
}

View File

@ -0,0 +1,98 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2009, Red Hat, Inc. and/or its affiliates or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program 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 this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.test.annotations.entity;
import java.io.Serializable;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import org.hibernate.HibernateException;
import org.hibernate.usertype.UserType;
/**
* Used to persist and retrieve objects of type 'PhoneNumber'
*
* @author Sharath Reddy
*/
public class OverseasPhoneNumberType implements UserType {
public int[] sqlTypes() {
return new int[]{Types.VARCHAR};
}
public Class returnedClass() {
return PhoneNumber.class;
}
public boolean equals(Object x, Object y) throws HibernateException {
return ( x == y ) || ( x != null && x.equals( y ) );
}
public int hashCode(Object x) throws HibernateException {
return x.hashCode();
}
public Object nullSafeGet(ResultSet rs, String[] names, Object owner) throws HibernateException, SQLException {
String result = rs.getString( names[0] );
if ( rs.wasNull() ) return null;
return new PhoneNumber(result);
}
public void nullSafeSet(PreparedStatement st, Object value, int index) throws HibernateException, SQLException {
if ( value == null ) {
st.setNull( index, sqlTypes()[0] );
}
else {
PhoneNumber phoneNumber = (PhoneNumber) value;
st.setString( index, getCountryCode() + phoneNumber.getNumber() );
}
}
private String getCountryCode() {
return "041";
}
public Object deepCopy(Object value) throws HibernateException {
return value;
}
public boolean isMutable() {
return false;
}
public Serializable disassemble(Object value) throws HibernateException {
return (Serializable) value;
}
public Object assemble(Serializable cached, Object owner) throws HibernateException {
return cached;
}
public Object replace(Object original, Object target, Object owner) throws HibernateException {
return original;
}
}

View File

@ -0,0 +1,48 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2009, Red Hat, Inc. and/or its affiliates or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program 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 this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.test.annotations.entity;
import javax.persistence.Entity;
import org.hibernate.annotations.Parameter;
import org.hibernate.annotations.TypeDef;
@TypeDef(
name = "definedInDerivedClass",
typeClass = CasterStringType.class,
parameters = {
@Parameter(name = "cast", value = "upper")
}
)
/**
* Defines a custom type that is used in the
* base class.
* @author Sharath Reddy
*
*/
@Entity
public class Peugot extends Car {
}

View File

@ -0,0 +1,42 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2009, Red Hat, Inc. and/or its affiliates or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program 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 this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.test.annotations.entity;
public class PhoneNumber {
private String number;
public PhoneNumber(String val) {
number = val;
}
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
}

View File

@ -0,0 +1,93 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2009, Red Hat, Inc. and/or its affiliates or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program 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 this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.test.annotations.entity;
import java.io.Serializable;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import org.hibernate.HibernateException;
import org.hibernate.usertype.UserType;
/**
* Used to persist and retrieve objects of type 'PhoneNumber'
*
* @author Sharath Reddy
*/
public class PhoneNumberType implements UserType {
public int[] sqlTypes() {
return new int[]{Types.VARCHAR};
}
public Class returnedClass() {
return PhoneNumber.class;
}
public boolean equals(Object x, Object y) throws HibernateException {
return ( x == y ) || ( x != null && x.equals( y ) );
}
public int hashCode(Object x) throws HibernateException {
return x.hashCode();
}
public Object nullSafeGet(ResultSet rs, String[] names, Object owner) throws HibernateException, SQLException {
String result = rs.getString( names[0] );
if ( rs.wasNull() ) return null;
return new PhoneNumber(result);
}
public void nullSafeSet(PreparedStatement st, Object value, int index) throws HibernateException, SQLException {
if ( value == null ) {
st.setNull( index, sqlTypes()[0] );
}
else {
PhoneNumber phoneNumber = (PhoneNumber) value;
st.setString( index, phoneNumber.getNumber() );
}
}
public Object deepCopy(Object value) throws HibernateException {
return value;
}
public boolean isMutable() {
return false;
}
public Serializable disassemble(Object value) throws HibernateException {
return (Serializable) value;
}
public Object assemble(Serializable cached, Object owner) throws HibernateException {
return cached;
}
public Object replace(Object original, Object target, Object owner) throws HibernateException {
return original;
}
}