HHH-15554 Add test for issue

This commit is contained in:
Andrea Boriero 2022-10-03 17:16:43 +02:00 committed by Andrea Boriero
parent 35d7d571f2
commit 89bd029bce
12 changed files with 1106 additions and 1 deletions

View File

@ -7,6 +7,7 @@
package org.hibernate.orm.test.annotations.embeddables; package org.hibernate.orm.test.annotations.embeddables;
import java.util.Arrays; import java.util.Arrays;
import java.util.Objects;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -45,7 +46,9 @@ public class EmbeddableWithManyToManyTest {
Product product = new Product( 2L, "Sugar", new Users( user ) ); Product product = new Product( 2L, "Sugar", new Users( user ) );
Product mergedProduct = session.merge( product ); Product mergedProduct = session.merge( product );
assertThat( mergedProduct.getUsers().getUsers() ).isNotNull(); Set<User> users = mergedProduct.getUsers().getUsers();
assertThat( users ).isNotNull();
assertThat( users ).contains( user );
} }
); );
@ -135,5 +138,23 @@ public class EmbeddableWithManyToManyTest {
public String getName() { public String getName() {
return name; return name;
} }
@Override
public boolean equals(Object o) {
if ( this == o ) {
return true;
}
if ( o == null || getClass() != o.getClass() ) {
return false;
}
User user = (User) o;
return Objects.equals( id, user.id ) && Objects.equals( name, user.name );
}
@Override
public int hashCode() {
return Objects.hash( id, name );
}
} }
} }

View File

@ -0,0 +1,186 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* 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.orm.test.cut;
import java.io.Serializable;
/**
* Class for testing composite user types with more than two fields.
*
* @author Etienne Miret
*/
public class CompositeDateTime implements Serializable {
private static final long serialVersionUID = 7401750071679578453L;
private Integer year;
private Integer month;
private Integer day;
private Integer hour;
private Integer minute;
private Integer second;
public CompositeDateTime(final Integer year, final Integer month, final Integer day, final Integer hour,
final Integer minute, final Integer second) {
super();
this.year = year;
this.month = month;
this.day = day;
this.hour = hour;
this.minute = minute;
this.second = second;
}
/*
* Constructor for those who hate auto (un)boxing.
*/
public CompositeDateTime(final int year, final int month, final int day, final int hour,
final int minute, final int second) {
this( new Integer( year ), Integer.valueOf( month ), Integer.valueOf( day ), Integer.valueOf( hour ),
Integer.valueOf( minute ), Integer.valueOf( second ) );
}
public CompositeDateTime(final CompositeDateTime other) {
super();
this.year = other.year;
this.month = other.month;
this.day = other.day;
this.hour = other.hour;
this.minute = other.minute;
this.second = other.second;
}
public Integer getYear() {
return year;
}
public void setYear(final Integer year) {
this.year = year;
}
public Integer getMonth() {
return month;
}
public void setMonth(final Integer month) {
this.month = month;
}
public Integer getDay() {
return day;
}
public void setDay(final Integer day) {
this.day = day;
}
public Integer getHour() {
return hour;
}
public void setHour(final Integer hour) {
this.hour = hour;
}
public Integer getMinute() {
return minute;
}
public void setMinute(final Integer minute) {
this.minute = minute;
}
public Integer getSecond() {
return second;
}
public void setSecond(final Integer second) {
this.second = second;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ( ( day == null ) ? 0 : day.hashCode() );
result = prime * result + ( ( hour == null ) ? 0 : hour.hashCode() );
result = prime * result + ( ( minute == null ) ? 0 : minute.hashCode() );
result = prime * result + ( ( month == null ) ? 0 : month.hashCode() );
result = prime * result + ( ( second == null ) ? 0 : second.hashCode() );
result = prime * result + ( ( year == null ) ? 0 : year.hashCode() );
return result;
}
@Override
public boolean equals(Object obj) {
if ( this == obj ) {
return true;
}
if ( obj == null ) {
return false;
}
if ( !( obj instanceof CompositeDateTime ) ) {
return false;
}
CompositeDateTime other = (CompositeDateTime) obj;
if ( day == null ) {
if ( other.day != null ) {
return false;
}
}
else if ( !day.equals( other.day ) ) {
return false;
}
if ( hour == null ) {
if ( other.hour != null ) {
return false;
}
}
else if ( !hour.equals( other.hour ) ) {
return false;
}
if ( minute == null ) {
if ( other.minute != null ) {
return false;
}
}
else if ( !minute.equals( other.minute ) ) {
return false;
}
if ( month == null ) {
if ( other.month != null ) {
return false;
}
}
else if ( !month.equals( other.month ) ) {
return false;
}
if ( second == null ) {
if ( other.second != null ) {
return false;
}
}
else if ( !second.equals( other.second ) ) {
return false;
}
if ( year == null ) {
if ( other.year != null ) {
return false;
}
}
else if ( !year.equals( other.year ) ) {
return false;
}
return true;
}
}

View File

@ -0,0 +1,107 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* 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.orm.test.cut;
import java.io.Serializable;
import org.hibernate.HibernateException;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.metamodel.spi.ValueAccess;
import org.hibernate.usertype.CompositeUserType;
/**
* Class for testing composite user types with more than two fields.
*
* @author Etienne Miret
*/
public class CompositeDateTimeUserType implements CompositeUserType<CompositeDateTime> {
@Override
public Object getPropertyValue(CompositeDateTime dateTime, int property) throws HibernateException {
switch ( property ) {
case 0:
return dateTime.getYear();
case 1:
return dateTime.getMonth();
case 2:
return dateTime.getDay();
case 3:
return dateTime.getHour();
case 4:
return dateTime.getMinute();
case 5:
return dateTime.getSecond();
default:
throw new HibernateException( "This type has only 6 fields." );
}
}
@Override
public CompositeDateTime instantiate(ValueAccess values, SessionFactoryImplementor sessionFactory) {
Integer year = values.getValue( 0, Integer.class );
Integer month = values.getValue( 1, Integer.class );
Integer day = values.getValue( 2, Integer.class );
Integer hour = values.getValue( 3, Integer.class );
Integer minute = values.getValue( 4, Integer.class );
Integer second = values.getValue( 5, Integer.class );
if ( year == null && month == null && day == null && hour == null && minute == null && second == null ) {
return null;
}
return new CompositeDateTime( year, month, day, hour, minute, second );
}
@Override
public Class<?> embeddable() {
return CompositeDateTime.class;
}
@Override
public Class<CompositeDateTime> returnedClass() {
return CompositeDateTime.class;
}
@Override
public boolean equals(CompositeDateTime x, CompositeDateTime y) throws HibernateException {
return x == null ? y == null : x.equals( y );
}
@Override
public int hashCode(CompositeDateTime x) throws HibernateException {
return x == null ? 0 : x.hashCode();
}
@Override
public CompositeDateTime deepCopy(CompositeDateTime value) throws HibernateException {
return value == null ? null : new CompositeDateTime( value );
}
@Override
public boolean isMutable() {
return true;
}
@Override
public Serializable disassemble(CompositeDateTime value) {
return deepCopy( value );
}
@Override
public CompositeDateTime assemble(Serializable cached, Object owner) {
return deepCopy( (CompositeDateTime) cached );
}
@Override
public CompositeDateTime replace(CompositeDateTime original, CompositeDateTime managed, Object owner) {
return deepCopy( original );
}
}

View File

@ -0,0 +1,310 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* 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.orm.test.cut;
import java.math.BigDecimal;
import java.util.Currency;
import java.util.List;
import org.hibernate.dialect.DB2Dialect;
import org.hibernate.dialect.HSQLDialect;
import org.hibernate.dialect.SybaseASEDialect;
import org.hibernate.query.Query;
import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.hibernate.testing.orm.junit.SkipForDialect;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
/**
* @author Gavin King
*/
@DomainModel(
xmlMappings = {
"org/hibernate/orm/test/cut/Transaction.hbm.xml"
}
)
@SessionFactory
public class CompositeUserTypeTest {
@AfterEach
public void tearDown(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
session.createMutationQuery( "delete from Transaction" ).executeUpdate();
session.createMutationQuery( "delete from MutualFund" ).executeUpdate();
}
);
}
@Test
public void testCompositeUserType(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
Transaction tran = new Transaction();
tran.setDescription( "a small transaction" );
tran.setValue( new MonetoryAmount( new BigDecimal( 1.5 ), Currency.getInstance( "USD" ) ) );
session.persist( tran );
List<Transaction> result = session.createQuery(
"from Transaction tran where tran.value.amount > 1.0 and tran.value.currency = 'USD'",
Transaction.class
)
.list();
assertEquals( 1, result.size() );
tran.getValue().setCurrency( Currency.getInstance( "AUD" ) );
result = session.createQuery(
"from Transaction tran where tran.value.amount > 1.0 and tran.value.currency = 'AUD'",
Transaction.class
)
.list();
assertEquals( 1, result.size() );
if ( !( scope.getSessionFactory().getJdbcServices().getDialect() instanceof HSQLDialect ) ) {
result = session.createQuery(
"from Transaction txn where txn.value = (1.5, 'AUD')",
Transaction.class
)
.list();
assertEquals( result.size(), 1 );
result = session.createQuery(
"" +
"from Transaction where value = (1.5, 'AUD')",
Transaction.class
)
.list();
assertEquals( result.size(), 1 );
result = session.createQuery(
"from Transaction where value != (1.4, 'AUD')",
Transaction.class
).list();
assertEquals( result.size(), 1 );
}
}
);
}
@Test
@SkipForDialect(dialectClass = SybaseASEDialect.class, reason = "HHH-6788")
@SkipForDialect(dialectClass = DB2Dialect.class, reason = "HHH-6867")
public void testCustomColumnReadAndWrite(SessionFactoryScope scope) {
final BigDecimal AMOUNT = new BigDecimal( 73000000d );
final BigDecimal AMOUNT_MILLIONS = AMOUNT.divide( new BigDecimal( 1000000d ) );
MutualFund f = new MutualFund();
f.setHoldings( new MonetoryAmount( AMOUNT, Currency.getInstance( "USD" ) ) );
scope.inTransaction(
session -> {
session.persist( f );
session.flush();
// Test value conversion during insert
BigDecimal amountViaSql = session.createNativeQuery(
"select amount_millions from MutualFund", BigDecimal.class )
.uniqueResult();
assertEquals( AMOUNT_MILLIONS.doubleValue(), amountViaSql.doubleValue(), 0.01d );
// Test projection
BigDecimal amountViaHql = session.createQuery(
"select f.holdings.amount from MutualFund f", BigDecimal.class )
.uniqueResult();
assertEquals( AMOUNT.doubleValue(), amountViaHql.doubleValue(), 0.01d );
BigDecimal one = new BigDecimal( 1 );
// Test restriction and entity load via criteria
// Test predicate and entity load via HQL
MutualFund mutualFund = (MutualFund) session.createQuery(
"from MutualFund f where f.holdings.amount between ?1 and ?2", MutualFund.class )
.setParameter( 1, AMOUNT.subtract( one ), BigDecimal.class )
.setParameter( 2, AMOUNT.add( one ), BigDecimal.class )
.uniqueResult();
assertEquals( AMOUNT.doubleValue(), mutualFund.getHoldings().getAmount().doubleValue(), 0.01d );
}
);
}
/**
* Tests the {@code =} operator on composite types.
*/
@Test
public void testEqualOperator(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
final Transaction txn = new Transaction();
txn.setDescription( "foo" );
txn.setValue( new MonetoryAmount( new BigDecimal( 42 ), Currency.getInstance( "AUD" ) ) );
txn.setTimestamp( new CompositeDateTime( 2014, 8, 23, 14, 35, 0 ) );
session.persist( txn );
final Query<Transaction> q = session.createQuery(
"from Transaction where value = :amount",
Transaction.class
);
/* Both amount and currency match. */
q.setParameter(
"amount",
new MonetoryAmount( new BigDecimal( 42 ), Currency.getInstance( "AUD" ) )
);
assertEquals( 1, q.list().size() );
/* Only currency matches. */
q.setParameter(
"amount",
new MonetoryAmount( new BigDecimal( 36 ), Currency.getInstance( "AUD" ) )
);
assertEquals( 0, q.list().size() );
/* Only amount matches. */
q.setParameter(
"amount",
new MonetoryAmount( new BigDecimal( 42 ), Currency.getInstance( "EUR" ) )
);
assertEquals( 0, q.list().size() );
/* None match. */
q.setParameter(
"amount",
new MonetoryAmount( new BigDecimal( 76 ), Currency.getInstance( "USD" ) )
);
assertEquals( 0, q.list().size() );
final Query<Transaction> qTimestamp = session.createQuery(
"from Transaction where timestamp = :timestamp",
Transaction.class
);
/* All matches. */
qTimestamp.setParameter( "timestamp", new CompositeDateTime( 2014, 8, 23, 14, 35, 0 ) );
assertEquals( 1, qTimestamp.list().size() );
/* None matches. */
qTimestamp.setParameter( "timestamp", new CompositeDateTime( 2013, 9, 25, 12, 31, 25 ) );
assertEquals( 0, qTimestamp.list().size() );
/* Year doesn't match. */
qTimestamp.setParameter( "timestamp", new CompositeDateTime( 2013, 8, 23, 14, 35, 0 ) );
assertEquals( 0, qTimestamp.list().size() );
/* Month doesn't match. */
qTimestamp.setParameter( "timestamp", new CompositeDateTime( 2014, 9, 23, 14, 35, 0 ) );
assertEquals( 0, qTimestamp.list().size() );
/* Minute doesn't match. */
qTimestamp.setParameter( "timestamp", new CompositeDateTime( 2014, 8, 23, 14, 41, 0 ) );
assertEquals( 0, qTimestamp.list().size() );
/* Second doesn't match. */
qTimestamp.setParameter( "timestamp", new CompositeDateTime( 2014, 8, 23, 14, 35, 28 ) );
assertEquals( 0, qTimestamp.list().size() );
}
);
}
@Test
@TestForIssue(jiraKey = "HHH-5946")
public void testNotEqualOperator(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
final Transaction t1 = new Transaction();
t1.setDescription( "foo" );
t1.setValue( new MonetoryAmount( new BigDecimal( 178 ), Currency.getInstance( "EUR" ) ) );
t1.setTimestamp( new CompositeDateTime( 2014, 8, 23, 14, 23, 0 ) );
session.persist( t1 );
final Transaction t2 = new Transaction();
t2.setDescription( "bar" );
t2.setValue( new MonetoryAmount( new BigDecimal( 1000000 ), Currency.getInstance( "USD" ) ) );
t1.setTimestamp( new CompositeDateTime( 2014, 8, 22, 14, 23, 0 ) );
session.persist( t2 );
final Transaction t3 = new Transaction();
t3.setDescription( "bar" );
t3.setValue( new MonetoryAmount( new BigDecimal( 1000000 ), Currency.getInstance( "EUR" ) ) );
t3.setTimestamp( new CompositeDateTime( 2014, 8, 22, 14, 23, 01 ) );
session.persist( t3 );
final Query q1 = session.createQuery( "from Transaction where value <> :amount" );
q1.setParameter(
"amount",
new MonetoryAmount( new BigDecimal( 178 ), Currency.getInstance( "EUR" ) )
);
assertEquals( 2, q1.list().size() );
final Query q2 = session.createQuery(
"from Transaction where value <> :amount and description = :str" );
q2.setParameter(
"amount",
new MonetoryAmount( new BigDecimal( 1000000 ), Currency.getInstance( "USD" ) )
);
q2.setParameter( "str", "bar" );
assertEquals( 1, q2.list().size() );
final Query q3 = session.createQuery( "from Transaction where timestamp <> :timestamp" );
q3.setParameter( "timestamp", new CompositeDateTime( 2014, 8, 23, 14, 23, 0 ) );
assertEquals( 2, q3.list().size() );
}
);
}
@Test
@TestForIssue(jiraKey = "HHH-5946")
public void testLessThanOperator(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
final Query q = session.createQuery( "from Transaction where value < :amount", Transaction.class );
q.setParameter( "amount", new MonetoryAmount( BigDecimal.ZERO, Currency.getInstance( "EUR" ) ) );
q.list();
}
);
}
@Test
@TestForIssue(jiraKey = "HHH-5946")
public void testLessOrEqualOperator(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
final Query q = session.createQuery( "from Transaction where value <= :amount", Transaction.class );
q.setParameter( "amount", new MonetoryAmount( BigDecimal.ZERO, Currency.getInstance( "USD" ) ) );
q.list();
}
);
}
@Test
@TestForIssue(jiraKey = "HHH-5946")
public void testGreaterThanOperator(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
final Query q = session.createQuery( "from Transaction where value > :amount", Transaction.class );
q.setParameter( "amount", new MonetoryAmount( BigDecimal.ZERO, Currency.getInstance( "EUR" ) ) );
q.list();
}
);
}
@Test
@TestForIssue(jiraKey = "HHH-5946")
public void testGreaterOrEqualOperator(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
final Query q = session.createQuery( "from Transaction where value >= :amount", Transaction.class );
q.setParameter( "amount", new MonetoryAmount( BigDecimal.ZERO, Currency.getInstance( "USD" ) ) );
q.list();
}
);
}
}

View File

@ -0,0 +1,78 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* 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.orm.test.cut;
import java.math.BigDecimal;
import java.util.Currency;
import java.util.List;
import org.hibernate.annotations.CompositeType;
import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.junit.jupiter.api.Test;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import static org.assertj.core.api.Assertions.assertThat;
@DomainModel(
annotatedClasses = ImmutableCompositeUserTypeTest.Wallet.class
)
@SessionFactory
@TestForIssue( jiraKey = "HHH-15554")
public class ImmutableCompositeUserTypeTest {
@Test
public void testImmutableCutMerge(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
ImmutableMonetoryAmount monetoryAmount = new ImmutableMonetoryAmount(
new BigDecimal( 1.5 ),
Currency.getInstance( "USD" )
);
Wallet wallet = new Wallet( 1, monetoryAmount );
session.merge( wallet );
List<Wallet> wallets = session.createQuery(
"from Wallet w where w.amount.amount > 1.0 and w.amount.currency = 'USD'" ).list();
assertThat( wallets.size() ).isEqualTo( 1 );
}
);
}
@Entity(name = "Wallet")
@Table(name = "Wallet_TABLE")
public static class Wallet {
@Id
private Integer id;
@CompositeType(value = ImmutableMonetoryAmountUserType.class)
private ImmutableMonetoryAmount amount;
public Wallet() {
}
public Wallet(Integer id, ImmutableMonetoryAmount amount) {
this.id = id;
this.amount = amount;
}
public Integer getId() {
return id;
}
public ImmutableMonetoryAmount getAmount() {
return amount;
}
}
}

View File

@ -0,0 +1,26 @@
package org.hibernate.orm.test.cut;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Currency;
public class ImmutableMonetoryAmount implements Serializable {
private BigDecimal amount;
private Currency currency;
public ImmutableMonetoryAmount(BigDecimal amount, Currency currency) {
this.amount = amount;
this.currency = currency;
}
public BigDecimal getAmount() {
return amount;
}
public Currency getCurrency() {
return currency;
}
}

View File

@ -0,0 +1,90 @@
package org.hibernate.orm.test.cut;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Currency;
import org.hibernate.HibernateException;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.metamodel.spi.ValueAccess;
import org.hibernate.usertype.CompositeUserType;
public class ImmutableMonetoryAmountUserType implements CompositeUserType<ImmutableMonetoryAmount> {
@Override
public Object getPropertyValue(ImmutableMonetoryAmount component, int property) throws HibernateException {
return property == 0 ? component.getAmount() : component.getCurrency();
}
@Override
public ImmutableMonetoryAmount instantiate(ValueAccess valueAccess, SessionFactoryImplementor sessionFactory) {
final BigDecimal value = valueAccess.getValue( 0, BigDecimal.class );
final Currency currency = valueAccess.getValue( 1, Currency.class );
if ( value == null && currency == null ) {
return null;
}
return new ImmutableMonetoryAmount( value, currency );
}
@Override
public Class<?> embeddable() {
return ImmutableMonetoryAmount.class;
}
@Override
public Class returnedClass() {
return ImmutableMonetoryAmount.class;
}
@Override
public boolean equals(ImmutableMonetoryAmount x, ImmutableMonetoryAmount y) throws HibernateException {
if ( x == y ) {
return true;
}
if ( x == null || y == null ) {
return false;
}
return x.getAmount().equals( y.getAmount() ) &&
x.getCurrency().equals( y.getCurrency() );
}
@Override
public int hashCode(ImmutableMonetoryAmount x) throws HibernateException {
return x.getAmount().hashCode();
}
@Override
public ImmutableMonetoryAmount deepCopy(ImmutableMonetoryAmount value) throws HibernateException {
return new ImmutableMonetoryAmount( value.getAmount(), value.getCurrency() );
}
@Override
public boolean isMutable() {
return false;
}
@Override
public Serializable disassemble(ImmutableMonetoryAmount value)
throws HibernateException {
return deepCopy( value );
}
@Override
public ImmutableMonetoryAmount assemble(Serializable cached, Object owner)
throws HibernateException {
return deepCopy( (ImmutableMonetoryAmount) cached );
}
@Override
public ImmutableMonetoryAmount replace(
ImmutableMonetoryAmount original,
ImmutableMonetoryAmount target,
Object owner)
throws HibernateException {
return deepCopy( original ); //TODO: improve
}
}

View File

@ -0,0 +1,43 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* 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>.
*/
//$Id: MonetoryAmount.java 6234 2005-03-29 03:07:30Z oneovthafew $
package org.hibernate.orm.test.cut;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Currency;
/**
* @author Gavin King
*/
public class MonetoryAmount implements Serializable {
private BigDecimal amount;
private Currency currency;
public MonetoryAmount(BigDecimal amount, Currency currency) {
this.amount = amount;
this.currency = currency;
}
public BigDecimal getAmount() {
return amount;
}
public void setAmount(BigDecimal amount) {
this.amount = amount;
}
public Currency getCurrency() {
return currency;
}
public void setCurrency(Currency currency) {
this.currency = currency;
}
}

View File

@ -0,0 +1,100 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* 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.orm.test.cut;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Currency;
import org.hibernate.HibernateException;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.metamodel.spi.ValueAccess;
import org.hibernate.usertype.CompositeUserType;
/**
* @author Gavin King
*/
public class MonetoryAmountUserType implements CompositeUserType<MonetoryAmount> {
@Override
public Object getPropertyValue(MonetoryAmount component, int property) throws HibernateException {
return property == 0 ? component.getAmount() : component.getCurrency();
}
@Override
public MonetoryAmount instantiate(ValueAccess valueAccess, SessionFactoryImplementor sessionFactory) {
final BigDecimal value = valueAccess.getValue( 0, BigDecimal.class );
final Currency currency = valueAccess.getValue( 1, Currency.class );
if ( value == null && currency == null ) {
return null;
}
return new MonetoryAmount( value, currency );
}
@Override
public Class<?> embeddable() {
return MonetoryAmount.class;
}
@Override
public Class returnedClass() {
return MonetoryAmount.class;
}
@Override
public boolean equals(MonetoryAmount x, MonetoryAmount y) throws HibernateException {
if ( x == y ) {
return true;
}
if ( x == null || y == null ) {
return false;
}
return x.getAmount().equals( y.getAmount() ) &&
x.getCurrency().equals( y.getCurrency() );
}
@Override
public int hashCode(MonetoryAmount x) throws HibernateException {
return x.getAmount().hashCode();
}
@Override
public MonetoryAmount deepCopy(MonetoryAmount value) throws HibernateException {
return new MonetoryAmount( value.getAmount(), value.getCurrency() );
}
@Override
public boolean isMutable() {
return true;
}
@Override
public Serializable disassemble(MonetoryAmount value)
throws HibernateException {
return deepCopy( value );
}
@Override
public MonetoryAmount assemble(Serializable cached, Object owner)
throws HibernateException {
return deepCopy( (MonetoryAmount) cached );
}
@Override
public MonetoryAmount replace(MonetoryAmount original, MonetoryAmount target, Object owner)
throws HibernateException {
return deepCopy( original ); //TODO: improve
}
// public static class MonetaryAmountEmbeddable {
// private BigDecimal amount;
// private Currency currency;
// }
}

View File

@ -0,0 +1,35 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* 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.orm.test.cut;
/**
* @author Rob.Hasselbaum
*
*/
public class MutualFund {
private Long id;
private MonetoryAmount holdings;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public MonetoryAmount getHoldings() {
return holdings;
}
public void setHoldings(MonetoryAmount holdings) {
this.holdings = holdings;
}
}

View File

@ -0,0 +1,55 @@
<?xml version="1.0"?>
<!--
~ Hibernate, Relational Persistence for Idiomatic Java
~
~ 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>.
-->
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<!--
Demonstrates the use of a CompositeUserType.
-->
<hibernate-mapping package="org.hibernate.orm.test.cut">
<class name="Transaction" table="Trnsctn">
<id name="id">
<generator class="native"/>
</id>
<property name="description" length="100" not-null="true"/>
<component name="value" class="org.hibernate.orm.test.cut.MonetoryAmountUserType">
<property name="amount" not-null="true"/>
<property name="currency" not-null="true"/>
</component>
<component name="timestamp" class="org.hibernate.orm.test.cut.CompositeDateTimeUserType">
<property name="year" column="ts_year"/>
<property name="month" column="ts_month"/>
<property name="day" column="ts_day"/>
<property name="hour" column="ts_hour"/>
<property name="minute" column="ts_minute"/>
<property name="second" column="ts_second"/>
</component>
</class>
<class name="MutualFund" table="MutualFund">
<id name="id">
<generator class="native"/>
</id>
<component name="holdings" class="org.hibernate.orm.test.cut.MonetoryAmountUserType">
<property name ="amount">
<column name="amount_millions"
not-null="true"
read="amount_millions * 1000000.0"
write="? / 1000000.0"/>
</property>
<property name="currency" not-null="true"/>
</component>
</class>
</hibernate-mapping>

View File

@ -0,0 +1,54 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* 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>.
*/
//$Id: Transaction.java 6234 2005-03-29 03:07:30Z oneovthafew $
package org.hibernate.orm.test.cut;
/**
* @author Gavin King
*/
public class Transaction {
private Long id;
private String description;
private MonetoryAmount value;
private CompositeDateTime timestamp;
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public MonetoryAmount getValue() {
return value;
}
public void setValue(MonetoryAmount value) {
this.value = value;
}
public CompositeDateTime getTimestamp() {
return timestamp;
}
public void setTimestamp(CompositeDateTime timestamp) {
this.timestamp = timestamp;
}
}