#908 - Remove support for Immutable Compound Values

This commit is contained in:
Rob Bygrave committed 2016-12-02 22:49:00 +13:00
1 parent 0aad285f35
commit cc989af1c6
60 files changed
+37 -2862

No files matched your search

@@ -4,15 +4,11 @@ import com.avaje.ebean.BaseTestCase;
import com.avaje.ebean.config.ServerConfig;
import com.avaje.ebean.config.dbplatform.H2Platform;
import com.avaje.ebeaninternal.server.core.bootup.BootupClasses;
import com.avaje.ebeaninternal.server.type.CtCompoundType;
import com.avaje.ebeaninternal.server.type.DefaultTypeManager;
import com.avaje.ebeaninternal.server.type.RsetDataReader;
import com.avaje.ebeaninternal.server.type.ScalarDataReader;
import com.avaje.ebeaninternal.server.type.ScalarType;
import com.avaje.ebeaninternal.server.type.reflect.CheckImmutableResponse;
import com.avaje.tests.model.ivo.CMoney;
import com.avaje.tests.model.ivo.ExhangeCMoneyRate;
import com.avaje.tests.model.ivo.Money;
import com.avaje.tests.model.ivo.converter.MoneyTypeConverter;
import org.junit.Assert;
import org.junit.Test;
@@ -76,20 +72,7 @@ public class TestTypeManager extends BaseTestCase {
DefaultTypeManager typeManager = createTypeManager();
CheckImmutableResponse checkImmutable = typeManager.checkImmutable(Money.class);
Assert.assertTrue(checkImmutable.isImmutable());
checkImmutable = typeManager.checkImmutable(CMoney.class);
Assert.assertTrue(checkImmutable.isImmutable());
ScalarDataReader<?> dataReader = typeManager
.recursiveCreateScalarDataReader(ExhangeCMoneyRate.class);
Assert.assertTrue(dataReader instanceof CtCompoundType<?>);
dataReader = typeManager.recursiveCreateScalarDataReader(CMoney.class);
Assert.assertTrue(dataReader instanceof CtCompoundType<?>);
ScalarType<?> scalarType = typeManager.recursiveCreateScalarTypes(Money.class);
ScalarType<?> scalarType = typeManager.getScalarType(Money.class);
Assert.assertTrue(scalarType.getJdbcType() == Types.DECIMAL);
Assert.assertTrue(!scalarType.isJdbcNative());
Assert.assertEquals(Money.class, scalarType.getType());
@@ -102,6 +85,7 @@ public class TestTypeManager extends BaseTestCase {
serverConfig.setDatabasePlatform(new H2Platform());
BootupClasses bootupClasses = new BootupClasses();
bootupClasses.getAttributeConverters().add(MoneyTypeConverter.class);
return new DefaultTypeManager(serverConfig, bootupClasses);
}
@@ -7,7 +7,6 @@ import com.avaje.ebean.plugin.ExpressionPath;
import com.avaje.ebean.plugin.SpiServer;
import com.avaje.ebean.text.json.JsonContext;
import com.avaje.tests.model.ddd.DPerson;
import com.avaje.tests.model.ivo.CMoney;
import com.avaje.tests.model.ivo.Money;
import org.junit.Test;
@@ -27,7 +26,6 @@ public class TestDPersonEl {
p.setFirstName("first");
p.setLastName("last");
p.setSalary(new Money("12200"));
p.setCmoney(new CMoney(new Money("12"), NZD));
Ebean.save(p);
@@ -42,26 +40,16 @@ public class TestDPersonEl {
DPerson bean = jsonContext.toBean(DPerson.class, json);
assertEquals("first", bean.getFirstName());
assertEquals(new Money("12200"), bean.getSalary());
assertEquals(new Money("12"), bean.getCmoney().getAmount());
assertEquals(NZD, bean.getCmoney().getCurrency());
EntityBean entityBean = (EntityBean) p;
ExpressionPath elCmoney = descriptor.getExpressionPath("cmoney");
ExpressionPath elCmoneyAmt = descriptor.getExpressionPath("cmoney.amount");
ExpressionPath elCmoneyCur = descriptor.getExpressionPath("cmoney.currency");
ExpressionPath elSalary = descriptor.getExpressionPath("salary");
Object cmoney = elCmoney.pathGet(entityBean);
Object amt = elCmoneyAmt.pathGet(entityBean);
Object cur = elCmoneyCur.pathGet(entityBean);
Object money = elSalary.pathGet(entityBean);
assertNotNull(cmoney);
assertEquals(new Money("12"), amt);
assertEquals(NZD, cur);
p.setCmoney(null);
assertNull(p.getCmoney());
assertNotNull(money);
assertEquals(new Money("12200"), money);
}
@@ -1,6 +1,5 @@
package com.avaje.tests.model.ddd;
import com.avaje.tests.model.ivo.ExhangeCMoneyRate;
import com.avaje.tests.model.ivo.Oid;
import javax.persistence.Entity;
@@ -14,7 +13,7 @@ public class DExhEntity {
@Id
Oid<DExhEntity> oid;
ExhangeCMoneyRate exhange;
String exhange;
@Version
Timestamp lastUpdated;
@@ -27,11 +26,11 @@ public class DExhEntity {
this.oid = oid;
}
public ExhangeCMoneyRate getExhange() {
public String getExhange() {
return exhange;
}
public void setExhange(ExhangeCMoneyRate exhange) {
public void setExhange(String exhange) {
this.exhange = exhange;
}
@@ -1,9 +1,7 @@
package com.avaje.tests.model.ddd;
import com.avaje.tests.model.ivo.CMoney;
import com.avaje.tests.model.ivo.Money;
import com.avaje.tests.model.ivo.Oid;
import org.joda.time.Interval;
import javax.persistence.Entity;
import javax.persistence.Id;
@@ -20,10 +18,6 @@ public class DPerson {
Money salary;
CMoney cmoney;
Interval interval;
public String toString() {
return id + " " + firstName + " " + lastName + " " + salary;
}
@@ -60,20 +54,4 @@ public class DPerson {
this.salary = salary;
}
public CMoney getCmoney() {
return cmoney;
}
public void setCmoney(CMoney cmoney) {
this.cmoney = cmoney;
}
public Interval getInterval() {
return interval;
}
public void setInterval(Interval interval) {
this.interval = interval;
}
}
@@ -1,27 +0,0 @@
package com.avaje.tests.model.ivo;
import java.util.Currency;
/**
* Currency and Money.
*
* @author rbygrave
*/
public class CMoney {
private final Money amount;
private final Currency currency;
public CMoney(Money amount, Currency currency) {
this.amount = amount;
this.currency = currency;
}
public Money getAmount() {
return amount;
}
public Currency getCurrency() {
return currency;
}
}
@@ -11,11 +11,11 @@ public class ESomeConvertType {
String name;
Rate rate;
Money money;
public ESomeConvertType(String name, Rate rate) {
public ESomeConvertType(String name, Money money) {
this.name = name;
this.rate = rate;
this.money = money;
}
public Long getId() {
@@ -34,11 +34,11 @@ public class ESomeConvertType {
this.name = name;
}
public Rate getRate() {
return rate;
public Money getMoney() {
return money;
}
public void setRate(Rate rate) {
this.rate = rate;
public void setMoney(Money money) {
this.money = money;
}
}
@@ -1,46 +0,0 @@
package com.avaje.tests.model.ivo;
/**
* Test compound type with nested compound type.
*/
public class ExhangeCMoneyRate {
private final Rate rate;
private final CMoney cmoney;
public ExhangeCMoneyRate(Rate rate, CMoney cmoney) {
this.rate = rate;
this.cmoney = cmoney;
}
public Rate getRate() {
return rate;
}
public CMoney getCmoney() {
return cmoney;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof ExhangeCMoneyRate) {
ExhangeCMoneyRate e = (ExhangeCMoneyRate) obj;
return e.rate.equals(rate) && e.cmoney.equals(cmoney);
}
return false;
}
@Override
public int hashCode() {
int hc = rate.hashCode();
hc = hc * 31 + cmoney.hashCode();
return hc;
}
@Override
public String toString() {
return "rate=" + rate + " cmoney=" + cmoney;
}
}
@@ -1,134 +0,0 @@
package com.avaje.tests.model.ivo;
import java.io.Serializable;
import java.math.BigDecimal;
import java.math.MathContext;
/**
* A representation of a Rate (like Tax or Discount) that is typically
* used to multiple against an amount (like Money).
* <p>
* A Rate effectively wraps a BigDecimal with associated control over
* precision and scale.
* <p>
* Rates are typically used to multiple or divide against an amount.
* For example, you can't ADD a Rate to Money.
* </p>
*
* @author rbygrave
*/
public final class Rate implements Comparable<Rate>, Serializable {
private static final long serialVersionUID = 1L;
public static final Rate ZERO = new Rate(BigDecimal.ZERO);
public static final Rate ONE = new Rate(BigDecimal.ONE);
private final BigDecimal value;
public Rate(BigDecimal value) {
if (value == null) {
throw new NullPointerException("value can not be null");
}
this.value = value;
}
public Rate(double val) {
this(BigDecimal.valueOf(val));
}
public Rate(String val) {
this(new BigDecimal(val));
}
public String toString() {
return value.toString();
}
public int compareTo(Rate o) {
return value.compareTo(o.value);
}
@Override
public int hashCode() {
return value.hashCode();
}
@Override
public boolean equals(Object obj) {
if (obj instanceof Rate) {
// use BigDecimal.compareTo to handle scale differences
return value.compareTo(((Rate) obj).getValue()) == 0;
}
return false;
}
public BigDecimal getValue() {
return value;
}
public Rate subtract(Rate amt) {
BigDecimal b = value.subtract(amt.value);
return new Rate(b);
}
public Rate subtract(Rate amt, MathContext ctx) {
BigDecimal b = value.subtract(amt.value, ctx);
return new Rate(b);
}
public Rate add(Rate amt) {
BigDecimal b = value.add(amt.value);
return new Rate(b);
}
public Rate add(Rate amt, MathContext ctx) {
BigDecimal b = value.add(amt.value, ctx);
return new Rate(b);
}
/**
* A Rate times Money amount returns Money.
*/
public Money times(Money amount) {
return multiply(amount);
}
public Money multiply(Money amount) {
BigDecimal b = value.multiply(amount.getAmount());
return new Money(b);
}
public Rate multiply(Rate m) {
return multiply(m.value);
}
public Rate multiply(int val) {
return multiply(BigDecimal.valueOf(val));
}
public Rate multiply(float val) {
return multiply(BigDecimal.valueOf(val));
}
public Rate multiply(double val) {
return multiply(BigDecimal.valueOf(val));
}
public Rate multiply(BigDecimal m) {
BigDecimal b = value.multiply(m);
return new Rate(b);
}
public Rate divide(BigDecimal divisor) {
BigDecimal b = value.divide(divisor);
return new Rate(b);
}
public Rate divide(BigDecimal divisor, MathContext ctx) {
BigDecimal b = value.divide(divisor, ctx);
return new Rate(b);
}
}
@@ -1,30 +0,0 @@
package com.avaje.tests.model.ivo;
import com.avaje.ebeaninternal.server.type.reflect.KnownImmutable;
public class SimpleKnownImmutable implements KnownImmutable {
public boolean isKnownImmutable(Class<?> cls) {
// Check for all allowed property types...
if (cls.isPrimitive() || String.class.equals(cls) || Object.class.equals(cls)) {
return true;
}
if (java.util.Date.class.equals(cls) || java.sql.Date.class.equals(cls) || java.sql.Timestamp.class.equals(cls)) {
// treat as immutable even through they are not strictly so
return true;
}
if (java.math.BigDecimal.class.equals(cls) || java.math.BigInteger.class.equals(cls)) {
// treat as immutable (contain non-final fields)
return true;
}
if (Integer.class.equals(cls) || Long.class.equals(cls) || Double.class.equals(cls) || Float.class.equals(cls)
|| Short.class.equals(cls) || Byte.class.equals(cls) || Character.class.equals(cls)
|| Boolean.class.equals(cls)) {
return true;
}
return false;
}
}
@@ -1,65 +0,0 @@
package com.avaje.tests.model.ivo;
import com.avaje.ebean.BaseTestCase;
import com.avaje.ebeaninternal.server.type.reflect.CheckImmutable;
import com.avaje.ebeaninternal.server.type.reflect.CheckImmutableResponse;
import com.avaje.ebeaninternal.server.type.reflect.ImmutableMeta;
import com.avaje.ebeaninternal.server.type.reflect.ImmutableMetaFactory;
import org.junit.Assert;
import org.junit.Test;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.util.Currency;
public class TestCheckImmutable extends BaseTestCase {
@Test
public void test() {
SimpleKnownImmutable known = new SimpleKnownImmutable();
CheckImmutable check = new CheckImmutable(known);
CheckImmutableResponse response = check.checkImmutable(Money.class);
Assert.assertTrue(response.isImmutable());
Assert.assertTrue(!response.isCompoundType());
}
public void testMeta() {
ImmutableMetaFactory factory = new ImmutableMetaFactory();
ImmutableMeta meta = factory.createImmutableMeta(Money.class);
Assert.assertNotNull(meta);
Constructor<?> c = meta.getConstructor();
Class<?>[] parameterTypes = c.getParameterTypes();
Method[] readers = meta.getReaders();
Assert.assertTrue(parameterTypes.length == 1);
Assert.assertTrue(readers.length == 1);
Assert.assertEquals("getAmount", readers[0].getName());
Assert.assertEquals(BigDecimal.class, parameterTypes[0]);
meta = factory.createImmutableMeta(CMoney.class);
Assert.assertNotNull(meta);
c = meta.getConstructor();
parameterTypes = c.getParameterTypes();
readers = meta.getReaders();
Assert.assertTrue(parameterTypes.length == 2);
Assert.assertTrue(readers.length == 2);
Assert.assertEquals(Money.class, parameterTypes[0]);
Assert.assertEquals("getAmount", readers[0].getName());
Assert.assertEquals(Currency.class, parameterTypes[1]);
Assert.assertEquals("getCurrency", readers[1].getName());
}
}
@@ -1,53 +0,0 @@
package com.avaje.tests.model.ivo.converter;
import com.avaje.ebean.config.CompoundTypeProperty;
import com.avaje.tests.model.ivo.CMoney;
import com.avaje.tests.model.ivo.Money;
import java.util.Currency;
public class CMoneyCompoundType {//implements CompoundType<CMoney> {
@SuppressWarnings({"rawtypes"})
private CompoundTypeProperty[] props = {new PropertyMoney(), new PropertyCurrency()};
public CMoney create(Object[] v) {
return new CMoney((Money) v[0], (Currency) v[1]);
}
@SuppressWarnings("unchecked")
public CompoundTypeProperty<CMoney, ?>[] getProperties() {
return props;
}
static class PropertyMoney implements CompoundTypeProperty<CMoney, Money> {
public String getName() {
return "amount";
}
public Money getValue(CMoney valueObject) {
return valueObject.getAmount();
}
public int getDbType() {
return 0;
}
}
static class PropertyCurrency implements CompoundTypeProperty<CMoney, Currency> {
public String getName() {
return "currency";
}
public Currency getValue(CMoney valueObject) {
return valueObject.getCurrency();
}
public int getDbType() {
return 0;
}
}
}
@@ -1,52 +0,0 @@
package com.avaje.tests.model.ivo.converter;
import com.avaje.ebean.config.CompoundType;
import com.avaje.ebean.config.CompoundTypeProperty;
import com.avaje.tests.model.ivo.CMoney;
import com.avaje.tests.model.ivo.ExhangeCMoneyRate;
import com.avaje.tests.model.ivo.Rate;
public class ExhangeCompoundType implements CompoundType<ExhangeCMoneyRate> {
public ExhangeCMoneyRate create(Object[] propertyValues) {
return new ExhangeCMoneyRate((Rate) propertyValues[0], (CMoney) propertyValues[1]);
}
@SuppressWarnings({"unchecked", "rawtypes"})
public CompoundTypeProperty<ExhangeCMoneyRate, ?>[] getProperties() {
return new CompoundTypeProperty[]{new RateProp(), new CMoneyProp()};
}
static class RateProp implements CompoundTypeProperty<ExhangeCMoneyRate, Rate> {
public String getName() {
return "rate";
}
public Rate getValue(ExhangeCMoneyRate valueObject) {
return valueObject.getRate();
}
public int getDbType() {
return 0;
}
}
static class CMoneyProp implements CompoundTypeProperty<ExhangeCMoneyRate, CMoney> {
public String getName() {
return "cmoney";
}
public CMoney getValue(ExhangeCMoneyRate valueObject) {
return valueObject.getCmoney();
}
public int getDbType() {
return 0;
}
}
}
@@ -1,49 +0,0 @@
package com.avaje.tests.model.ivo.converter;
import com.avaje.ebean.config.CompoundType;
import com.avaje.ebean.config.CompoundTypeProperty;
import org.joda.time.Interval;
public class JodaIntervalCompoundType implements CompoundType<Interval> {
public Interval create(Object[] propertyValues) {
return new Interval((Long) propertyValues[0], (Long) propertyValues[1]);
}
@SuppressWarnings({"unchecked", "rawtypes"})
public CompoundTypeProperty<Interval, ?>[] getProperties() {
return new CompoundTypeProperty[]{new Start(), new End()};
}
static class Start implements CompoundTypeProperty<Interval, Long> {
public String getName() {
return "startMillis";
}
public Long getValue(Interval valueObject) {
return valueObject.getStartMillis();
}
public int getDbType() {
return java.sql.Types.TIMESTAMP;
}
}
static class End implements CompoundTypeProperty<Interval, Long> {
public String getName() {
return "endMillis";
}
public Long getValue(Interval valueObject) {
return valueObject.getEndMillis();
}
public int getDbType() {
return java.sql.Types.TIMESTAMP;
}
}
}
@@ -2,18 +2,19 @@ package com.avaje.tests.model.ivo.converter;
import com.avaje.tests.model.ivo.Money;
import javax.persistence.AttributeConverter;
import java.math.BigDecimal;
/**
* Converts between Money and BigDecimal.
*/
public class MoneyTypeConverter {//implements ScalarTypeConverter<Money,BigDecimal>{
public class MoneyTypeConverter implements AttributeConverter<Money,BigDecimal> {
public BigDecimal unwrapValue(Money beanType) {
public BigDecimal convertToDatabaseColumn(Money beanType) {
return beanType.getAmount();
}
public Money wrapValue(BigDecimal scalarType) {
public Money convertToEntityAttribute(BigDecimal scalarType) {
return new Money(scalarType);
}
@@ -1,8 +1,14 @@
package com.avaje.tests.model.ivo.converter;
import com.avaje.ebean.config.ScalarTypeConverter;
import com.avaje.tests.model.ivo.Oid;
public class OidTypeConverter {//implements ScalarTypeConverter<Oid<?>,Long> {
public class OidTypeConverter implements ScalarTypeConverter<Oid<?>,Long> {
@Override
public Oid<?> getNullValue() {
return null;
}
public Oid<?> wrapValue(Long scalarType) {
if (scalarType == null) {
@@ -1,24 +0,0 @@
package com.avaje.tests.model.ivo.converter;
import com.avaje.tests.model.ivo.Rate;
import javax.persistence.AttributeConverter;
import javax.persistence.Converter;
import java.math.BigDecimal;
/**
* Converts between Rate and BigDecimal.
*/
@Converter
public class RateTypeConverter implements AttributeConverter<Rate,BigDecimal> {
@Override
public BigDecimal convertToDatabaseColumn(Rate attribute) {
return attribute.getValue();
}
@Override
public Rate convertToEntityAttribute(BigDecimal dbData) {
return new Rate(dbData);
}
}
@@ -3,7 +3,7 @@ package com.avaje.tests.model.ivo.test;
import com.avaje.ebean.BaseTestCase;
import com.avaje.ebean.Ebean;
import com.avaje.tests.model.ivo.ESomeConvertType;
import com.avaje.tests.model.ivo.Rate;
import com.avaje.tests.model.ivo.Money;
import org.junit.Test;
public class TestAttributeConverter extends BaseTestCase {
@@ -11,12 +11,12 @@ public class TestAttributeConverter extends BaseTestCase {
@Test
public void insertUpdateDelete() {
ESomeConvertType bean = new ESomeConvertType("one", new Rate(20.1));
ESomeConvertType bean = new ESomeConvertType("one", new Money(20.1));
Ebean.save(bean);
ESomeConvertType found = Ebean.find(ESomeConvertType.class, bean.getId());
found.setRate(new Rate("40"));
found.setMoney(new Money("40"));
Ebean.save(found);
Ebean.delete(found);
@@ -4,7 +4,6 @@ import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Version;
import java.time.MonthDay;
import java.time.Period;
@Entity
public class SomePeriodBean {
@@ -15,8 +14,6 @@ public class SomePeriodBean {
@Version
Long version;
Period period;
MonthDay anniversary;
public Long getId() {
@@ -35,14 +32,6 @@ public class SomePeriodBean {
this.version = version;
}
public Period getPeriod() {
return period;
}
public void setPeriod(Period period) {
this.period = period;
}
public MonthDay getAnniversary() {
return anniversary;
}
@@ -8,26 +8,21 @@ import org.junit.Test;
import java.sql.Date;
import java.time.LocalDate;
import java.time.MonthDay;
import java.time.Period;
import java.util.List;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
/**
*/
public class TestPeriodType extends BaseTestCase {
@Test
public void testInsert() {
SomePeriodBean bean = new SomePeriodBean();
bean.setPeriod(Period.of(3, 4, 5));
bean.setAnniversary(MonthDay.of(4, 29));
Ebean.save(bean);
SomePeriodBean bean1 = Ebean.find(SomePeriodBean.class, bean.getId());
assertEquals(bean.getPeriod(), bean1.getPeriod());
assertEquals(bean.getAnniversary(), bean1.getAnniversary());
// insert fetch null value
@@ -35,14 +30,11 @@ public class TestPeriodType extends BaseTestCase {
Ebean.save(bean2);
SomePeriodBean bean3 = Ebean.find(SomePeriodBean.class, bean2.getId());
assertNull(bean3.getPeriod());
assertNull(bean3.getAnniversary());
List<SomePeriodBean> anniversaryList = Ebean.find(SomePeriodBean.class)
.where()
.eq("anniversary", MonthDay.of(4, 29))
.eq("period_years", 3)
.eq("period_months", 4)
.findList();
assertEquals(1, anniversaryList.size());