diff --git a/src/main/java/com/aerospike/mapper/tools/configuration/ClassConfig.java b/src/main/java/com/aerospike/mapper/tools/configuration/ClassConfig.java index 034e0bf..d9e53c2 100644 --- a/src/main/java/com/aerospike/mapper/tools/configuration/ClassConfig.java +++ b/src/main/java/com/aerospike/mapper/tools/configuration/ClassConfig.java @@ -9,6 +9,7 @@ import com.aerospike.mapper.annotations.AerospikeEmbed; import com.aerospike.mapper.annotations.AerospikeReference; import com.aerospike.mapper.tools.ConfigurationUtils; +import com.aerospike.mapper.tools.mappers.BooleanMapper; import com.fasterxml.jackson.annotation.JsonProperty; public class ClassConfig { @@ -26,11 +27,17 @@ public class ClassConfig { private String factoryClass; private String factoryMethod; private final List bins; + private BooleanMapper.Encoding boolEncoding = BooleanMapper.Encoding.Numeric; + public ClassConfig() { bins = new ArrayList<>(); } + public BooleanMapper.Encoding getBoolEncoding() { + return boolEncoding; + } + public String getClassName() { return className; } @@ -163,16 +170,21 @@ private void setKey(KeyConfig key) { private void setShortName(String shortName) { this.shortName = shortName; } - + + private void setBoolEncoding( BooleanMapper.Encoding boolEncoding) { + this.boolEncoding = boolEncoding; + } + public static class Builder { private final Class clazz; private final ClassConfig classConfig; + public Builder(final Class clazz) { this.clazz = clazz; this.classConfig = new ClassConfig(); this.classConfig.setClassName(clazz.getName()); } - + private void validateFieldExists(String fieldName) { if (!ConfigurationUtils.validateFieldOnClass(this.clazz, fieldName)) { throw new AerospikeException(String.format("Field %s does not exist on class %s or its superclasses", fieldName, this.clazz)); @@ -199,6 +211,11 @@ public Builder withTtl(int ttl) { return this; } + public Builder withBoolEncoding(BooleanMapper.Encoding boolEncoding) { + this.classConfig.setBoolEncoding(boolEncoding); + return this; + } + public Builder withVersion(int version) { this.classConfig.setVersion(version); return this; @@ -223,7 +240,7 @@ public Builder withShortName(boolean sendKey) { this.classConfig.setSendKey(sendKey); return this; } - + public Builder withFactoryClassAndMethod(@NotNull Class factoryClass, @NotNull String factoryMethod) { this.classConfig.setFactoryClass(factoryClass.getName()); this.classConfig.setFactoryMethod(factoryMethod); diff --git a/src/main/java/com/aerospike/mapper/tools/mappers/BooleanMapper.java b/src/main/java/com/aerospike/mapper/tools/mappers/BooleanMapper.java index 55958d7..181171a 100644 --- a/src/main/java/com/aerospike/mapper/tools/mappers/BooleanMapper.java +++ b/src/main/java/com/aerospike/mapper/tools/mappers/BooleanMapper.java @@ -1,13 +1,37 @@ package com.aerospike.mapper.tools.mappers; +import com.aerospike.mapper.tools.ClassCache; import com.aerospike.mapper.tools.TypeMapper; +import com.aerospike.mapper.tools.configuration.ClassConfig; import static com.aerospike.client.Value.UseBoolBin; public class BooleanMapper extends TypeMapper { + public enum Encoding { + Numeric, + Boolean + } + + private final ClassConfig classConfig; + + public BooleanMapper(final ClassConfig config) { + super(); + classConfig = config; + } + @Override public Object toAerospikeFormat(Object value) { + if (ClassCache.getInstance().hasClassConfig(Boolean.class)) { + UseBoolBin = ClassCache.getInstance() + .getClassConfig(Boolean.class) + .getBoolEncoding() + .equals(Encoding.Boolean); + } else { + UseBoolBin = false; + } + + if (value == null) { return null; } diff --git a/src/main/java/com/aerospike/mapper/tools/utils/TypeUtils.java b/src/main/java/com/aerospike/mapper/tools/utils/TypeUtils.java index b5d84fb..d4a5b34 100644 --- a/src/main/java/com/aerospike/mapper/tools/utils/TypeUtils.java +++ b/src/main/java/com/aerospike/mapper/tools/utils/TypeUtils.java @@ -111,7 +111,8 @@ private static TypeMapper getMapper(Class clazz, AnnotatedType type, IBaseAer } else if (Integer.class.isAssignableFrom(clazz) || Integer.TYPE.isAssignableFrom(clazz)) { typeMapper = new IntMapper(); } else if (Boolean.class.isAssignableFrom(clazz) || Boolean.TYPE.isAssignableFrom(clazz)) { - typeMapper = new BooleanMapper(); + ClassConfig config = ClassCache.getInstance().getClassConfig(clazz); + typeMapper = new BooleanMapper(config); } else if (Float.class.isAssignableFrom(clazz) || Float.TYPE.isAssignableFrom(clazz)) { typeMapper = new FloatMapper(); } else if (clazz.isEnum()) { diff --git a/src/test/java/com/aerospike/mapper/BooleanTest.java b/src/test/java/com/aerospike/mapper/BooleanTest.java new file mode 100644 index 0000000..82dd6a7 --- /dev/null +++ b/src/test/java/com/aerospike/mapper/BooleanTest.java @@ -0,0 +1,104 @@ +package com.aerospike.mapper; + +import com.aerospike.client.Key; +import com.aerospike.client.Record; +import com.aerospike.client.policy.Policy; +import com.aerospike.mapper.annotations.AerospikeKey; +import com.aerospike.mapper.annotations.AerospikeRecord; +import com.aerospike.mapper.tools.AeroMapper; +import com.fasterxml.jackson.core.JsonProcessingException; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class BooleanTest extends AeroMapperBaseTest { + @AerospikeRecord(namespace = "test", set = "B") + public static class B { + @AerospikeKey + public int id; + public Boolean boolValue; + } + + @Test + public void testNumericEncoding() throws JsonProcessingException { + B b = new B(); + b.boolValue = true; + b.id = 1; + String config = + "---\n" + + "classes:\n" + + " - class: com.aerospike.mapper.BooleanTest$B\n" + + " namespace: test\n" + + " set: B\n" + + " key:\n" + + " field: id\n" + + " - class: java.lang.Boolean\n" + + " boolEncoding: Numeric\n"; + + AeroMapper mapper = new AeroMapper.Builder(client).withConfiguration(config).build(); + mapper.save(b); + + B b2 = mapper.read(B.class, 1); + + assertEquals(b.id, b2.id); + assertEquals(b.boolValue, b2.boolValue); + final Record rec = mapper.getClient().get(new Policy(), new Key("test", "B", 1)); + final Object rawRepresentation = rec.bins.get("boolValue"); + assertEquals(Long.class, rawRepresentation.getClass()); + } + + @Test + public void testObjectEncoding() throws JsonProcessingException { + B b = new B(); + b.boolValue = true; + b.id = 1; + String config = + "---\n" + + "classes:\n" + + " - class: com.aerospike.mapper.BooleanTest$B\n" + + " namespace: test\n" + + " set: B\n" + + " key:\n" + + " field: id\n" + + " - class: java.lang.Boolean\n" + + " boolEncoding: Boolean\n"; + + AeroMapper mapper = new AeroMapper.Builder(client).withConfiguration(config).build(); + mapper.save(b); + + B b2 = mapper.read(B.class, 1); + + assertEquals(b.id, b2.id); + assertEquals(b.boolValue, b2.boolValue); + final Record rec = mapper.getClient().get(new Policy(), new Key("test", "B", 1)); + final Object rawRepresentation = rec.bins.get("boolValue"); + assertEquals(Boolean.class, rawRepresentation.getClass()); + } + + @Test + public void testNumericByDefault() throws JsonProcessingException { + B b = new B(); + b.boolValue = true; + b.id = 1; + String config = + "---\n" + + "classes:\n" + + " - class: com.aerospike.mapper.BooleanTest$B\n" + + " namespace: test\n" + + " set: B\n" + + " key:\n" + + " field: id\n"; + + AeroMapper mapper = new AeroMapper.Builder(client).withConfiguration(config).build(); + mapper.save(b); + + B b2 = mapper.read(B.class, 1); + + assertEquals(b.id, b2.id); + assertEquals(b.boolValue, b2.boolValue); + final Record rec = mapper.getClient().get(new Policy(), new Key("test", "B", 1)); + final Object rawRepresentation = rec.bins.get("boolValue"); + assertEquals(Long.class, rawRepresentation.getClass()); + } + +} diff --git a/src/test/java/com/aerospike/mapper/DefaultFieldValuesTest.java b/src/test/java/com/aerospike/mapper/DefaultFieldValuesTest.java index 7577f8c..fb16b6a 100644 --- a/src/test/java/com/aerospike/mapper/DefaultFieldValuesTest.java +++ b/src/test/java/com/aerospike/mapper/DefaultFieldValuesTest.java @@ -87,7 +87,7 @@ public void testBooleanValue() { UseBoolBin = true; mapper.save(obj); record = client.get(null, key); - assertTrue(record.bins.get("bool2") instanceof Boolean); + assertTrue(record.bins.get("bool2") instanceof Long); assertFalse(record.getBoolean("bool2")); dfc = mapper.read(DefaultFieldsClass.class, "dfc"); assertFalse(dfc.bool2);