Add BigDecimal converter.

Add BigDecimal converter, add converter tests for BigDecimal and BigInteger.
Since BigDecimail is not support, it cannot be used in the CustomerConverter tests.
So instead use ChoiceFormat for CustomConverter tests.

Closes #1439.
This commit is contained in:
Michael Reiche
2022-06-14 16:50:07 -07:00
parent a038c1b4d4
commit 1db04d2cf5
2 changed files with 173 additions and 50 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2021 the original author or authors
* Copyright 2021-2022 the original author or authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,6 +16,7 @@
package org.springframework.data.couchbase.core.convert;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Collection;
@@ -47,6 +48,8 @@ public final class OtherConverters {
converters.add(StringToUuid.INSTANCE);
converters.add(BigIntegerToString.INSTANCE);
converters.add(StringToBigInteger.INSTANCE);
converters.add(BigDecimalToString.INSTANCE);
converters.add(StringToBigDecimal.INSTANCE);
return converters;
}
@@ -90,4 +93,24 @@ public final class OtherConverters {
return source == null ? null : new BigInteger(source);
}
}
@WritingConverter
public enum BigDecimalToString implements Converter<BigDecimal, String> {
INSTANCE;
@Override
public String convert(BigDecimal source) {
return source == null ? null : source.toPlainString();
}
}
@ReadingConverter
public enum StringToBigDecimal implements Converter<String, BigDecimal> {
INSTANCE;
@Override
public BigDecimal convert(String source) {
return source == null ? null : new BigDecimal(source);
}
}
}

View File

@@ -16,14 +16,32 @@
package org.springframework.data.couchbase.core.mapping;
import static org.assertj.core.api.Assertions.*;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.assertj.core.data.Offset.offset;
import static org.junit.jupiter.api.Assertions.*;
import static org.junit.jupiter.api.Assertions.assertThrows;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.text.ChoiceFormat;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.UUID;
import java.util.stream.Collectors;
import org.junit.jupiter.api.Test;
import org.springframework.core.convert.converter.Converter;
@@ -35,7 +53,11 @@ import org.springframework.data.convert.WritingConverter;
import org.springframework.data.couchbase.core.convert.CouchbaseCustomConversions;
import org.springframework.data.couchbase.core.convert.CouchbaseJsr310Converters.LocalDateTimeToLongConverter;
import org.springframework.data.couchbase.core.convert.MappingCouchbaseConverter;
import org.springframework.data.couchbase.core.mapping.id.*;
import org.springframework.data.couchbase.core.mapping.id.GeneratedValue;
import org.springframework.data.couchbase.core.mapping.id.GenerationStrategy;
import org.springframework.data.couchbase.core.mapping.id.IdAttribute;
import org.springframework.data.couchbase.core.mapping.id.IdPrefix;
import org.springframework.data.couchbase.core.mapping.id.IdSuffix;
import org.springframework.data.couchbase.domain.Address;
import org.springframework.data.couchbase.domain.Config;
import org.springframework.data.couchbase.domain.Person;
@@ -70,8 +92,9 @@ public class MappingCouchbaseConverterTests {
void doesNotAllowSimpleType1() {
try {
converter.write("hello", new CouchbaseDocument());
} catch(Exception e){
if(!(e instanceof MappingException) && !e.getClass().getName().equals("java.lang.reflect.InaccessibleObjectException")){
} catch (Exception e) {
if (!(e instanceof MappingException)
&& !e.getClass().getName().equals("java.lang.reflect.InaccessibleObjectException")) {
throw new RuntimeException("Should have thrown MappingException or InaccessibleObjectException", e);
}
}
@@ -81,8 +104,9 @@ public class MappingCouchbaseConverterTests {
void doesNotAllowSimpleType2() {
try {
converter.write(true, new CouchbaseDocument());
} catch(Exception e){
if(!(e instanceof MappingException) && !e.getClass().getName().equals("java.lang.reflect.InaccessibleObjectException")){
} catch (Exception e) {
if (!(e instanceof MappingException)
&& !e.getClass().getName().equals("java.lang.reflect.InaccessibleObjectException")) {
throw new RuntimeException("Should have thrown MappingException or InaccessibleObjectException", e);
}
}
@@ -92,8 +116,9 @@ public class MappingCouchbaseConverterTests {
void doesNotAllowSimpleType3() {
try {
converter.write(42, new CouchbaseDocument());
} catch(Exception e){
if(!(e instanceof MappingException) && !e.getClass().getName().equals("java.lang.reflect.InaccessibleObjectException")){
} catch (Exception e) {
if (!(e instanceof MappingException)
&& !e.getClass().getName().equals("java.lang.reflect.InaccessibleObjectException")) {
throw new RuntimeException("Should have thrown MappingException or InaccessibleObjectException", e);
}
}
@@ -112,7 +137,7 @@ public class MappingCouchbaseConverterTests {
converter.write(entity, converted);
Map<String, Object> result = converted.export();
assertThat(result.get("_class")).isEqualTo(entity.getClass().getName());
assertThat(result.get("attr0")).isEqualTo("foobar");
assertThat(result.get("attr0")).isEqualTo(entity.attr0);
assertThat(converted.getId()).isEqualTo(BaseEntity.ID);
}
@@ -123,7 +148,51 @@ public class MappingCouchbaseConverterTests {
source.put("attr0", "foobar");
StringEntity converted = converter.read(StringEntity.class, source);
assertThat(converted.attr0).isEqualTo("foobar");
assertThat(converted.attr0).isEqualTo(source.get("attr0"));
}
@Test
void writesBigInteger() {
CouchbaseDocument converted = new CouchbaseDocument();
BigIntegerEntity entity = new BigIntegerEntity(new BigInteger("12345"));
converter.write(entity, converted);
Map<String, Object> result = converted.export();
assertThat(result.get("_class")).isEqualTo(entity.getClass().getName());
assertThat(result.get("attr0")).isEqualTo(entity.attr0.toString());
assertThat(converted.getId()).isEqualTo(BaseEntity.ID);
}
@Test
void readsBigInteger() {
CouchbaseDocument source = new CouchbaseDocument();
source.put("_class", BigIntegerEntity.class.getName());
source.put("attr0", "12345");
BigIntegerEntity converted = converter.read(BigIntegerEntity.class, source);
assertThat(converted.attr0).isEqualTo(new BigInteger((String) source.get("attr0")));
}
@Test
void writesBigDecimal() {
CouchbaseDocument converted = new CouchbaseDocument();
BigDecimalEntity entity = new BigDecimalEntity(new BigDecimal("123.45"));
converter.write(entity, converted);
Map<String, Object> result = converted.export();
assertThat(result.get("_class")).isEqualTo(entity.getClass().getName());
assertThat(result.get("attr0")).isEqualTo(entity.attr0.toString());
assertThat(converted.getId()).isEqualTo(BaseEntity.ID);
}
@Test
void readsBigDecimal() {
CouchbaseDocument source = new CouchbaseDocument();
source.put("_class", BigDecimalEntity.class.getName());
source.put("attr0", "123.45");
BigDecimalEntity converted = converter.read(BigDecimalEntity.class, source);
assertThat(converted.attr0).isEqualTo(new BigDecimal((String) source.get("attr0")));
}
@Test
@@ -438,8 +507,8 @@ public class MappingCouchbaseConverterTests {
@Test
void writesAndReadsCustomConvertedClass() {
List<Object> converters = new ArrayList<>();
converters.add(BigDecimalToStringConverter.INSTANCE);
converters.add(StringToBigDecimalConverter.INSTANCE);
converters.add(ChoiceFormatToStringConverter.INSTANCE);
converters.add(StringToChoiceFormatConverter.INSTANCE);
CustomConversions customConversions = new CouchbaseCustomConversions(converters);
converter.setCustomConversions(customConversions);
converter.afterPropertiesSet();
@@ -448,14 +517,14 @@ public class MappingCouchbaseConverterTests {
CouchbaseDocument converted = new CouchbaseDocument();
final String valueStr = "12.345";
final BigDecimal value = new BigDecimal(valueStr);
final String value2Str = "0.6789";
final BigDecimal value2 = new BigDecimal(value2Str);
List<BigDecimal> listOfValues = new ArrayList<>();
final String valueStr = "1.0,2.0,3.0,4.0,5.0,6.0,7.0|Sun,Mon,Tue,Wed,Thur,Fri,Sat";
final ChoiceFormat value = fromString(valueStr);
final String value2Str = "1.0,2.0,3.0|Jan,Feb,Mar";
final ChoiceFormat value2 = fromString(value2Str);
List<ChoiceFormat> listOfValues = new ArrayList<>();
listOfValues.add(value);
listOfValues.add(value2);
Map<String, BigDecimal> mapOfValues = new TreeMap<>();
Map<String, ChoiceFormat> mapOfValues = new TreeMap<>();
mapOfValues.put("val1", value);
mapOfValues.put("val2", value2);
@@ -486,11 +555,25 @@ public class MappingCouchbaseConverterTests {
assertThat(readConverted.mapOfValues.get("val2")).isEqualTo(mapOfValues.get("val2"));
}
static private String toString(ChoiceFormat choiceFormat) {
String limits = Arrays.stream(choiceFormat.getLimits()).mapToObj(String::valueOf).collect(Collectors.joining(","));
String formats = Arrays.stream(choiceFormat.getFormats()).map((o) -> String.valueOf(o))
.collect(Collectors.joining(","));
return limits + "|" + formats;
}
static private ChoiceFormat fromString(String source) {
String[] split = source.split("\\|");
double[] limits = Arrays.stream(split[0].split(",")).mapToDouble(Double::parseDouble).toArray();
String[] formats = split[1].split(",");
return new ChoiceFormat(limits, formats);
}
@Test
void writesAndReadsCustomFieldsConvertedClass() {
List<Object> converters = new ArrayList<>();
converters.add(BigDecimalToStringConverter.INSTANCE);
converters.add(StringToBigDecimalConverter.INSTANCE);
converters.add(ChoiceFormatToStringConverter.INSTANCE);
converters.add(StringToChoiceFormatConverter.INSTANCE);
CustomConversions customConversions = new CouchbaseCustomConversions(converters);
converter.setCustomConversions(customConversions);
converter.afterPropertiesSet();
@@ -499,14 +582,14 @@ public class MappingCouchbaseConverterTests {
CouchbaseDocument converted = new CouchbaseDocument();
final String valueStr = "12.345";
final BigDecimal value = new BigDecimal(valueStr);
final String value2Str = "0.6789";
final BigDecimal value2 = new BigDecimal(value2Str);
List<BigDecimal> listOfValues = new ArrayList<>();
final String valueStr = "1.0,2.0,3.0,4.0,5.0,6.0,7.0|Sun,Mon,Tue,Wed,Thur,Fri,Sat";
final ChoiceFormat value = fromString(valueStr);
final String value2Str = "1.0,2.0,3.0|Jan,Feb,Mar";
final ChoiceFormat value2 = fromString(value2Str);
List<ChoiceFormat> listOfValues = new ArrayList<>();
listOfValues.add(value);
listOfValues.add(value2);
Map<String, BigDecimal> mapOfValues = new HashMap<>();
Map<String, ChoiceFormat> mapOfValues = new TreeMap<>();
mapOfValues.put("val1", value);
mapOfValues.put("val2", value2);
@@ -515,18 +598,18 @@ public class MappingCouchbaseConverterTests {
CouchbaseDocument source = new CouchbaseDocument();
source.put("_class", CustomFieldsEntity.class.getName());
source.put("decimalValue", valueStr);
source.put("choiceFormatValue", valueStr);
CouchbaseList listOfValuesDoc = new CouchbaseList();
listOfValuesDoc.put(valueStr);
listOfValuesDoc.put(value2Str);
source.put("listOfDecimalValues", listOfValuesDoc);
source.put("listOfChoiceFormatValues", listOfValuesDoc);
CouchbaseDocument mapOfValuesDoc = new CouchbaseDocument();
mapOfValuesDoc.put("val1", valueStr);
mapOfValuesDoc.put("val2", value2Str);
source.put("mapOfDecimalValues", mapOfValuesDoc);
source.put("mapOfChoiceFormatValues", mapOfValuesDoc);
assertThat(valueStr).isEqualTo(((CouchbaseList) converted.getContent().get("listOfDecimalValues")).get(0));
assertThat(value2Str).isEqualTo(((CouchbaseList) converted.getContent().get("listOfDecimalValues")).get(1));
assertThat(valueStr).isEqualTo(((CouchbaseList) converted.getContent().get("listOfChoiceFormatValues")).get(0));
assertThat(value2Str).isEqualTo(((CouchbaseList) converted.getContent().get("listOfChoiceFormatValues")).get(1));
assertThat(converted.export().toString()).isEqualTo(source.export().toString());
CustomFieldsEntity readConverted = converter.read(CustomFieldsEntity.class, source);
@@ -540,8 +623,8 @@ public class MappingCouchbaseConverterTests {
@Test
void writesAndReadsClassContainingCustomConvertedObjects() {
List<Object> converters = new ArrayList<>();
converters.add(BigDecimalToStringConverter.INSTANCE);
converters.add(StringToBigDecimalConverter.INSTANCE);
converters.add(ChoiceFormatToStringConverter.INSTANCE);
converters.add(StringToChoiceFormatConverter.INSTANCE);
CustomConversions customConversions = new CouchbaseCustomConversions(converters);
converter.setCustomConversions(customConversions);
converter.afterPropertiesSet();
@@ -635,22 +718,22 @@ public class MappingCouchbaseConverterTests {
}
@WritingConverter
public enum BigDecimalToStringConverter implements Converter<BigDecimal, String> {
public enum ChoiceFormatToStringConverter implements Converter<ChoiceFormat, String> {
INSTANCE;
@Override
public String convert(BigDecimal source) {
return source.toPlainString();
public String convert(ChoiceFormat source) {
return MappingCouchbaseConverterTests.toString(source);
}
}
@ReadingConverter
public enum StringToBigDecimalConverter implements Converter<String, BigDecimal> {
public enum StringToChoiceFormatConverter implements Converter<String, ChoiceFormat> {
INSTANCE;
@Override
public BigDecimal convert(String source) {
return new BigDecimal(source);
public ChoiceFormat convert(String source) {
return MappingCouchbaseConverterTests.fromString(source);
}
}
@@ -676,6 +759,22 @@ public class MappingCouchbaseConverterTests {
}
}
static class BigIntegerEntity extends BaseEntity {
private BigInteger attr0;
public BigIntegerEntity(BigInteger attr0) {
this.attr0 = attr0;
}
}
static class BigDecimalEntity extends BaseEntity {
private BigDecimal attr0;
public BigDecimalEntity(BigDecimal attr0) {
this.attr0 = attr0;
}
}
static class NumberEntity extends BaseEntity {
private long attr0;
@@ -770,11 +869,11 @@ public class MappingCouchbaseConverterTests {
}
static class CustomEntity extends BaseEntity {
private BigDecimal value;
private List<BigDecimal> listOfValues;
private Map<String, BigDecimal> mapOfValues;
private ChoiceFormat value;
private List<ChoiceFormat> listOfValues;
private Map<String, ChoiceFormat> mapOfValues;
public CustomEntity(BigDecimal value, List<BigDecimal> listOfValues, Map<String, BigDecimal> mapOfValues) {
public CustomEntity(ChoiceFormat value, List<ChoiceFormat> listOfValues, Map<String, ChoiceFormat> mapOfValues) {
this.value = value;
this.listOfValues = listOfValues;
this.mapOfValues = mapOfValues;
@@ -782,11 +881,12 @@ public class MappingCouchbaseConverterTests {
}
static class CustomFieldsEntity extends BaseEntity {
@Field("decimalValue") private BigDecimal value;
@Field("listOfDecimalValues") private List<BigDecimal> listOfValues;
@Field("mapOfDecimalValues") private Map<String, BigDecimal> mapOfValues;
@Field("choiceFormatValue") private ChoiceFormat value;
@Field("listOfChoiceFormatValues") private List<ChoiceFormat> listOfValues;
@Field("mapOfChoiceFormatValues") private Map<String, ChoiceFormat> mapOfValues;
public CustomFieldsEntity(BigDecimal value, List<BigDecimal> listOfValues, Map<String, BigDecimal> mapOfValues) {
public CustomFieldsEntity(ChoiceFormat value, List<ChoiceFormat> listOfValues,
Map<String, ChoiceFormat> mapOfValues) {
this.value = value;
this.listOfValues = listOfValues;
this.mapOfValues = mapOfValues;