HHH-15554 Add test for issue
This commit is contained in:
parent
35d7d571f2
commit
89bd029bce
|
@ -7,6 +7,7 @@
|
|||
package org.hibernate.orm.test.annotations.embeddables;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
@ -45,7 +46,9 @@ public class EmbeddableWithManyToManyTest {
|
|||
|
||||
Product product = new Product( 2L, "Sugar", new Users( user ) );
|
||||
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() {
|
||||
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 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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 );
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
// }
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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>
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue