Skip to content

Commit 519087f

Browse files
authored
Permit unannotated embedded classes (#125)
* permit unannotated embedded classes * do not require AerospikeRecord annotation for base class on default mapAll configuration
1 parent e7922a5 commit 519087f

File tree

6 files changed

+223
-124
lines changed

6 files changed

+223
-124
lines changed

src/main/java/com/aerospike/mapper/tools/ClassCache.java

+19-16
Original file line numberDiff line numberDiff line change
@@ -18,27 +18,14 @@
1818
import java.util.Map;
1919

2020
public class ClassCache {
21-
private static final ClassCache instance = new ClassCache();
22-
23-
public static ClassCache getInstance() {
24-
return instance;
25-
}
26-
27-
enum PolicyType {
28-
READ,
29-
WRITE,
30-
BATCH,
31-
SCAN,
32-
QUERY
33-
}
3421

22+
private static final ClassCache instance = new ClassCache();
3523
private final Map<Class<?>, ClassCacheEntry<?>> cacheMap = new HashMap<>();
3624
private final Map<String, ClassConfig> classesConfig = new HashMap<>();
3725
private final Map<PolicyType, Policy> defaultPolicies = new HashMap<>();
3826
private final Map<String, ClassCacheEntry<?>> storedNameToCacheEntry = new HashMap<>();
3927
private final Map<PolicyType, Map<Class<?>, Policy>> childrenPolicies = new HashMap<>();
4028
private final Map<PolicyType, Map<Class<?>, Policy>> specificPolicies = new HashMap<>();
41-
4229
private final Object lock = new Object();
4330

4431
private ClassCache() {
@@ -48,8 +35,16 @@ private ClassCache() {
4835
}
4936
}
5037

51-
@SuppressWarnings("unchecked")
38+
public static ClassCache getInstance() {
39+
return instance;
40+
}
41+
5242
public <T> ClassCacheEntry<T> loadClass(@NotNull Class<T> clazz, IBaseAeroMapper mapper) {
43+
return loadClass(clazz, mapper, true);
44+
}
45+
46+
@SuppressWarnings("unchecked")
47+
public <T> ClassCacheEntry<T> loadClass(@NotNull Class<T> clazz, IBaseAeroMapper mapper, boolean requireRecord) {
5348
if (clazz.isPrimitive() || clazz.equals(Object.class) || clazz.equals(String.class)
5449
|| clazz.equals(Character.class) || Number.class.isAssignableFrom(clazz)) {
5550
return null;
@@ -69,7 +64,7 @@ public <T> ClassCacheEntry<T> loadClass(@NotNull Class<T> clazz, IBaseAeroMapper
6964
// public int id;
7065
// public A a;
7166
// }
72-
entry = new ClassCacheEntry<>(clazz, mapper, getClassConfig(clazz),
67+
entry = new ClassCacheEntry<>(clazz, mapper, getClassConfig(clazz), requireRecord,
7368
determinePolicy(clazz, PolicyType.READ),
7469
(WritePolicy) determinePolicy(clazz, PolicyType.WRITE),
7570
(BatchPolicy) determinePolicy(clazz, PolicyType.BATCH),
@@ -195,4 +190,12 @@ public boolean hasClassConfig(String className) {
195190
public boolean hasClassConfig(Class<?> clazz) {
196191
return classesConfig.containsKey(clazz.getName());
197192
}
193+
194+
enum PolicyType {
195+
READ,
196+
WRITE,
197+
BATCH,
198+
SCAN,
199+
QUERY
200+
}
198201
}

src/main/java/com/aerospike/mapper/tools/ClassCacheEntry.java

+19-34
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,5 @@
11
package com.aerospike.mapper.tools;
22

3-
import java.lang.annotation.Annotation;
4-
import java.lang.reflect.Constructor;
5-
import java.lang.reflect.Field;
6-
import java.lang.reflect.Method;
7-
import java.lang.reflect.Modifier;
8-
import java.lang.reflect.Parameter;
9-
import java.util.ArrayList;
10-
import java.util.Arrays;
11-
import java.util.HashMap;
12-
import java.util.HashSet;
13-
import java.util.List;
14-
import java.util.Map;
15-
import java.util.Set;
16-
import java.util.TreeMap;
17-
18-
import javax.validation.constraints.NotNull;
19-
20-
import org.apache.commons.lang3.StringUtils;
21-
223
import com.aerospike.client.AerospikeException;
234
import com.aerospike.client.Bin;
245
import com.aerospike.client.Key;
@@ -30,22 +11,24 @@
3011
import com.aerospike.client.policy.QueryPolicy;
3112
import com.aerospike.client.policy.ScanPolicy;
3213
import com.aerospike.client.policy.WritePolicy;
33-
import com.aerospike.mapper.annotations.AerospikeBin;
34-
import com.aerospike.mapper.annotations.AerospikeConstructor;
35-
import com.aerospike.mapper.annotations.AerospikeExclude;
36-
import com.aerospike.mapper.annotations.AerospikeGetter;
37-
import com.aerospike.mapper.annotations.AerospikeKey;
38-
import com.aerospike.mapper.annotations.AerospikeOrdinal;
39-
import com.aerospike.mapper.annotations.AerospikeRecord;
40-
import com.aerospike.mapper.annotations.AerospikeSetter;
41-
import com.aerospike.mapper.annotations.ParamFrom;
14+
import com.aerospike.mapper.annotations.*;
4215
import com.aerospike.mapper.exceptions.NotAnnotatedClass;
4316
import com.aerospike.mapper.tools.configuration.BinConfig;
4417
import com.aerospike.mapper.tools.configuration.ClassConfig;
4518
import com.aerospike.mapper.tools.configuration.KeyConfig;
4619
import com.aerospike.mapper.tools.utils.ParserUtils;
4720
import com.aerospike.mapper.tools.utils.TypeUtils;
4821
import com.aerospike.mapper.tools.utils.TypeUtils.AnnotatedType;
22+
import org.apache.commons.lang3.StringUtils;
23+
24+
import javax.validation.constraints.NotNull;
25+
import java.lang.annotation.Annotation;
26+
import java.lang.reflect.Constructor;
27+
import java.lang.reflect.Field;
28+
import java.lang.reflect.Method;
29+
import java.lang.reflect.Modifier;
30+
import java.lang.reflect.Parameter;
31+
import java.util.*;
4932

5033
public class ClassCacheEntry<T> {
5134

@@ -104,7 +87,7 @@ private enum FactoryMethodType {
10487
private volatile boolean constructed;
10588

10689
// package visibility only.
107-
ClassCacheEntry(@NotNull Class<T> clazz, IBaseAeroMapper mapper, ClassConfig config,
90+
ClassCacheEntry(@NotNull Class<T> clazz, IBaseAeroMapper mapper, ClassConfig config, boolean requireRecord,
10891
@NotNull Policy readPolicy, @NotNull WritePolicy writePolicy,
10992
@NotNull BatchPolicy batchPolicy, @NotNull QueryPolicy queryPolicy,
11093
@NotNull ScanPolicy scanPolicy) {
@@ -118,8 +101,9 @@ private enum FactoryMethodType {
118101
this.queryPolicy = queryPolicy;
119102

120103
AerospikeRecord recordDescription = clazz.getAnnotation(AerospikeRecord.class);
121-
if (recordDescription == null && config == null) {
122-
throw new NotAnnotatedClass("Class " + clazz.getName() + " is not augmented by the @AerospikeRecord annotation");
104+
if (requireRecord && recordDescription == null && config == null) {
105+
throw new NotAnnotatedClass(String.format("Class %s is not augmented by the @AerospikeRecord annotation",
106+
clazz.getName()));
123107
} else if (recordDescription != null) {
124108
this.namespace = ParserUtils.getInstance().get(recordDescription.namespace());
125109
this.setName = ParserUtils.getInstance().get(recordDescription.set());
@@ -143,10 +127,11 @@ public ClassCacheEntry<T> construct() {
143127

144128
this.loadFieldsFromClass();
145129
this.loadPropertiesFromClass();
146-
this.superClazz = ClassCache.getInstance().loadClass(this.clazz.getSuperclass(), this.mapper);
130+
this.superClazz = ClassCache.getInstance().loadClass(this.clazz.getSuperclass(), this.mapper, !this.mapAll);
147131
this.binCount = this.values.size() + (superClazz != null ? superClazz.binCount : 0);
148132
if (this.binCount == 0) {
149-
throw new AerospikeException("Class " + clazz.getSimpleName() + " has no values defined to be stored in the database");
133+
throw new AerospikeException(String.format("Class %s has no values defined to be stored in the database",
134+
clazz.getSimpleName()));
150135
}
151136
this.formOrdinalsFromValues();
152137
Method factoryConstructorMethod = findConstructorFactoryMethod();
@@ -240,7 +225,7 @@ public boolean isChildClass() {
240225

241226
private void checkRecordSettingsAgainstSuperClasses() {
242227
if (!StringUtils.isBlank(this.namespace) && !StringUtils.isBlank(this.setName)) {
243-
// This class defines it's own namespace + set, it is only a child class if it's closest named superclass is the same as ours.
228+
// This class defines its own namespace + set, it is only a child class if its closest named superclass is the same as ours.
244229
this.isChildClass = false;
245230
ClassCacheEntry<?> thisEntry = this.superClazz;
246231
while (thisEntry != null) {

src/main/java/com/aerospike/mapper/tools/mappers/ObjectEmbedMapper.java

+19-12
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
package com.aerospike.mapper.tools.mappers;
22

3-
import java.util.List;
4-
import java.util.Map;
5-
63
import com.aerospike.client.AerospikeException;
74
import com.aerospike.mapper.annotations.AerospikeEmbed.EmbedType;
85
import com.aerospike.mapper.tools.ClassCache;
96
import com.aerospike.mapper.tools.ClassCacheEntry;
107
import com.aerospike.mapper.tools.IBaseAeroMapper;
118

9+
import java.util.List;
10+
import java.util.Map;
11+
1212
public class ObjectEmbedMapper extends ObjectMapper {
1313

1414
private final Class<?> referencedClass;
@@ -28,10 +28,13 @@ public Object toAerospikeFormat(Object value) {
2828
if (value == null) {
2929
return null;
3030
}
31+
if (isSimple(value)) {
32+
return value;
33+
}
3134
// In this case we want to store a reference to the object.
3235
boolean needsType = !(referencedClass.equals(value.getClass()));
33-
// Use the actual class here in case a sub-class is passed. In that case needsType will be true
34-
ClassCacheEntry<?> entry = ClassCache.getInstance().loadClass(value.getClass(), mapper);
36+
// Use the actual class here in case a subclass is passed. In that case needsType will be true.
37+
ClassCacheEntry<?> entry = ClassCache.getInstance().loadClass(value.getClass(), mapper, false);
3538
switch (type) {
3639
case LIST:
3740
return entry.getList(value, skipKey, needsType);
@@ -50,25 +53,29 @@ public Object fromAerospikeFormat(Object value) {
5053
if (value == null) {
5154
return null;
5255
}
56+
if (isSimple(value)) {
57+
return value;
58+
}
5359
ClassCacheEntry<?> entry = ClassCache.getInstance().loadClass(referencedClass, mapper);
5460
try {
55-
Object instance;
56-
5761
switch (type) {
5862
case LIST:
5963
List<Object> listValue = (List<Object>) value;
60-
instance = entry.constructAndHydrate(listValue, skipKey);
61-
break;
64+
return entry.constructAndHydrate(listValue, skipKey);
6265
case MAP: // Fall through
6366
case DEFAULT:
64-
instance = entry.constructAndHydrate((Map<String, Object>) value);
65-
break;
67+
return entry.constructAndHydrate((Map<String, Object>) value);
6668
default:
6769
throw new AerospikeException("Unspecified EmbedType");
6870
}
69-
return instance;
7071
} catch (Exception e) {
7172
throw new AerospikeException(e);
7273
}
7374
}
75+
76+
private boolean isSimple(Object value) {
77+
Class<?> clazz = value.getClass();
78+
return clazz.isPrimitive() || clazz.equals(Object.class) || clazz.equals(String.class)
79+
|| clazz.equals(Character.class) || Number.class.isAssignableFrom(clazz);
80+
}
7481
}

src/main/java/com/aerospike/mapper/tools/utils/MapperUtils.java

+4
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@
77
import org.apache.commons.lang3.StringUtils;
88

99
public class MapperUtils {
10+
11+
private MapperUtils() {
12+
}
13+
1014
public static <T> ClassCacheEntry<T> getEntryAndValidateNamespace(Class<T> clazz, IBaseAeroMapper mapper) {
1115
ClassCacheEntry<T> entry = ClassCache.getInstance().loadClass(clazz, mapper);
1216
String namespace = null;

0 commit comments

Comments
 (0)