Skip to content

Commit 590cecd

Browse files
committed
PR ebean-orm#3143 - FEATURE: DbJson Support for Dto-Queries
1 parent 924f611 commit 590cecd

9 files changed

Lines changed: 325 additions & 19 deletions

File tree

ebean-core/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanProperty.java

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
* Description of a property of a bean. Includes its deployment information such
3636
* as database column mapping information.
3737
*/
38-
public class DeployBeanProperty {
38+
public class DeployBeanProperty implements DeployProperty {
3939

4040
private static final int ID_ORDER = 1000000;
4141
private static final int UNIDIRECTIONAL_ORDER = 100000;
@@ -226,6 +226,11 @@ public DeployBeanDescriptor<?> getDesc() {
226226
return desc;
227227
}
228228

229+
@Override
230+
public Class<?> getOwnerType() {
231+
return desc.getBeanType();
232+
}
233+
229234
/**
230235
* Return the DB column length for character columns.
231236
* <p>
@@ -258,10 +263,12 @@ public void setJsonDeserialize(boolean jsonDeserialize) {
258263
this.jsonDeserialize = jsonDeserialize;
259264
}
260265

266+
@Override
261267
public MutationDetection getMutationDetection() {
262268
return mutationDetection;
263269
}
264270

271+
@Override
265272
public void setMutationDetection(MutationDetection dirtyDetection) {
266273
this.mutationDetection = dirtyDetection;
267274
}
@@ -476,8 +483,9 @@ public void setGeneratedProperty(GeneratedProperty generatedValue) {
476483
}
477484

478485
/**
479-
* Return true if this property is mandatory.
486+
* Return true if this property is not mandatory.
480487
*/
488+
@Override
481489
public boolean isNullable() {
482490
return nullable;
483491
}
@@ -848,6 +856,7 @@ public Class<?> getPropertyType() {
848856
/**
849857
* Return the generic type for this property.
850858
*/
859+
@Override
851860
public Type getGenericType() {
852861
return genericType;
853862
}
@@ -1052,6 +1061,7 @@ public <A extends Annotation> A getMetaAnnotation(Class<A> annotationType) {
10521061
return null;
10531062
}
10541063

1064+
@Override
10551065
@SuppressWarnings("unchecked")
10561066
public <A extends Annotation> List<A> getMetaAnnotations(Class<A> annotationType) {
10571067
List<A> result = new ArrayList<>();
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package io.ebeaninternal.server.deploy.meta;
2+
3+
import io.ebean.annotation.MutationDetection;
4+
5+
import java.lang.annotation.Annotation;
6+
import java.lang.reflect.Type;
7+
import java.util.List;
8+
9+
/**
10+
* Property, with basic type information (BeanProperty and DtoProperty).
11+
*/
12+
public interface DeployProperty {
13+
14+
/**
15+
* Return the name of the property.
16+
*/
17+
String getName();
18+
19+
/**
20+
* Return the generic type for this property.
21+
*/
22+
Type getGenericType();
23+
24+
/**
25+
* Return the property type.
26+
*/
27+
Class<?> getPropertyType();
28+
29+
/**
30+
* Returns the owner class of this property.
31+
*/
32+
Class<?> getOwnerType();
33+
34+
/**
35+
* Returns the annotations on this property.
36+
*/
37+
<A extends Annotation> List<A> getMetaAnnotations(Class<A> annotationType);
38+
39+
/**
40+
* Returns the mutation detection setting of this property.
41+
*/
42+
MutationDetection getMutationDetection();
43+
44+
/**
45+
* Sets the mutation detection setting of this property.
46+
*/
47+
void setMutationDetection(MutationDetection mutationDetection);
48+
49+
/**
50+
* Return true if this property is not mandatory.
51+
*/
52+
boolean isNullable();
53+
}

ebean-core/src/main/java/io/ebeaninternal/server/deploy/parse/DeployUtil.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,7 @@ private void setDbJsonType(DeployBeanProperty prop, int dbType, int dbLength, Mu
224224
/**
225225
* Return the JDBC type for the JSON storage type.
226226
*/
227-
private int dbJsonStorage(DbJsonType dbJsonType) {
227+
public static int dbJsonStorage(DbJsonType dbJsonType) {
228228
switch (dbJsonType) {
229229
case JSONB:
230230
return DbPlatformType.JSONB;

ebean-core/src/main/java/io/ebeaninternal/server/dto/DtoMetaBuilder.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package io.ebeaninternal.server.dto;
22

3+
import io.ebean.annotation.DbJson;
4+
import io.ebean.annotation.DbJsonB;
35
import io.ebeaninternal.api.CoreLog;
46
import io.ebeaninternal.server.type.TypeManager;
57

@@ -21,10 +23,16 @@ final class DtoMetaBuilder {
2123
private final Class<?> dtoType;
2224
private final List<DtoMetaProperty> properties = new ArrayList<>();
2325
private final Map<Integer, DtoMetaConstructor> constructorMap = new HashMap<>();
26+
private final Set<Class<?>> annotationFilter = new HashSet<>();
2427

2528
DtoMetaBuilder(Class<?> dtoType, TypeManager typeManager) {
2629
this.dtoType = dtoType;
2730
this.typeManager = typeManager;
31+
annotationFilter.add(DbJson.class);
32+
annotationFilter.add(DbJsonB.class);
33+
if (typeManager.jsonMarkerAnnotation() != null) {
34+
annotationFilter.add(typeManager.jsonMarkerAnnotation());
35+
}
2836
}
2937

3038
DtoMeta build() {
@@ -38,7 +46,7 @@ private void readProperties() {
3846
if (includeMethod(method)) {
3947
try {
4048
final String name = propertyName(method.getName());
41-
properties.add(new DtoMetaProperty(typeManager, dtoType, method, name));
49+
properties.add(new DtoMetaProperty(typeManager, dtoType, method, name, annotationFilter));
4250
} catch (Exception e) {
4351
CoreLog.log.log(DEBUG, "exclude on " + dtoType + " method " + method, e);
4452
}
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
package io.ebeaninternal.server.dto;
2+
3+
import io.ebean.annotation.MutationDetection;
4+
import io.ebeaninternal.server.deploy.meta.DeployProperty;
5+
6+
import java.lang.annotation.Annotation;
7+
import java.lang.reflect.Method;
8+
import java.lang.reflect.Type;
9+
import java.util.ArrayList;
10+
import java.util.List;
11+
import java.util.Set;
12+
13+
/**
14+
* DeployProperty for Dto-Properties.
15+
*
16+
* @author Roland Praml, FOCONIS AG
17+
*/
18+
class DtoMetaDeployProperty implements DeployProperty {
19+
private final String name;
20+
private final Class<?> ownerType;
21+
private final Type genericType;
22+
private final Class<?> propertyType;
23+
private final Set<Annotation> metaAnnotations;
24+
private final boolean nullable;
25+
private MutationDetection mutationDetection = MutationDetection.DEFAULT;
26+
27+
DtoMetaDeployProperty(String name, Class<?> ownerType, Type genericType, Class<?> propertyType, Set<Annotation> metaAnnotations, Method method) {
28+
this.name = name;
29+
this.ownerType = ownerType;
30+
this.genericType = genericType;
31+
this.nullable = !propertyType.isPrimitive();
32+
this.propertyType = propertyType;
33+
this.metaAnnotations = metaAnnotations;
34+
}
35+
36+
@Override
37+
public String getName() {
38+
return name;
39+
}
40+
41+
@Override
42+
public Type getGenericType() {
43+
return genericType;
44+
}
45+
46+
@Override
47+
public Class<?> getPropertyType() {
48+
return propertyType;
49+
}
50+
51+
@Override
52+
public Class<?> getOwnerType() {
53+
return ownerType;
54+
}
55+
56+
@Override
57+
public <A extends Annotation> List<A> getMetaAnnotations(Class<A> annotationType) {
58+
List<A> result = new ArrayList<>();
59+
for (Annotation ann : metaAnnotations) {
60+
if (ann.annotationType() == annotationType) {
61+
result.add((A) ann);
62+
}
63+
}
64+
return result;
65+
}
66+
67+
@Override
68+
public MutationDetection getMutationDetection() {
69+
return mutationDetection;
70+
}
71+
72+
@Override
73+
public void setMutationDetection(MutationDetection mutationDetection) {
74+
this.mutationDetection = mutationDetection;
75+
}
76+
77+
@Override
78+
public boolean isNullable() {
79+
return nullable;
80+
}
81+
}

ebean-core/src/main/java/io/ebeaninternal/server/dto/DtoMetaProperty.java

Lines changed: 69 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,26 @@
11
package io.ebeaninternal.server.dto;
22

3+
import io.ebean.annotation.DbJson;
4+
import io.ebean.annotation.DbJsonB;
5+
import io.ebean.config.dbplatform.DbPlatformType;
36
import io.ebean.core.type.DataReader;
47
import io.ebean.core.type.ScalarType;
8+
import io.ebean.util.AnnotationUtil;
9+
import io.ebeaninternal.server.deploy.meta.DeployProperty;
10+
import io.ebeaninternal.server.deploy.parse.DeployUtil;
511
import io.ebeaninternal.server.type.TypeManager;
612

13+
import java.lang.annotation.Annotation;
714
import java.lang.invoke.MethodHandle;
815
import java.lang.invoke.MethodHandles;
916
import java.lang.invoke.MethodType;
17+
import java.lang.reflect.Field;
1018
import java.lang.reflect.Method;
1119
import java.lang.reflect.Type;
1220
import java.sql.SQLException;
21+
import java.util.Collections;
22+
import java.util.List;
23+
import java.util.Set;
1324

1425
final class DtoMetaProperty implements DtoReadSet {
1526

@@ -20,18 +31,74 @@ final class DtoMetaProperty implements DtoReadSet {
2031
private final MethodHandle setter;
2132
private final ScalarType<?> scalarType;
2233

23-
DtoMetaProperty(TypeManager typeManager, Class<?> dtoType, Method writeMethod, String name) throws IllegalAccessException, NoSuchMethodException {
34+
DtoMetaProperty(TypeManager typeManager, Class<?> dtoType, Method writeMethod, String name, Set<Class<?>> annotationFilter)
35+
throws IllegalAccessException, NoSuchMethodException {
2436
this.dtoType = dtoType;
2537
this.name = name;
2638
if (writeMethod != null) {
2739
this.setter = lookupMethodHandle(dtoType, writeMethod);
28-
this.scalarType = typeManager.type(propertyType(writeMethod), propertyClass(writeMethod));
40+
Field field = findField(dtoType, name);
41+
DeployProperty deployProp = new DtoMetaDeployProperty(name,
42+
dtoType,
43+
propertyType(writeMethod),
44+
propertyClass(writeMethod),
45+
field == null ? Collections.emptySet() : AnnotationUtil.metaFindAllFor(field, annotationFilter),
46+
writeMethod);
47+
scalarType = getScalarType(typeManager, deployProp);
2948
} else {
3049
this.scalarType = null;
3150
this.setter = null;
3251
}
3352
}
3453

54+
private ScalarType<?> getScalarType(TypeManager typeManager, DeployProperty deployProp) {
55+
final ScalarType<?> scalarType;
56+
57+
List<DbJson> json = deployProp.getMetaAnnotations(DbJson.class);
58+
if (!json.isEmpty()) {
59+
return typeManager.dbJsonType(deployProp, DeployUtil.dbJsonStorage(json.get(0).storage()), json.get(0).length());
60+
}
61+
List<DbJsonB> jsonB = deployProp.getMetaAnnotations(DbJsonB.class);
62+
if (!jsonB.isEmpty()) {
63+
return typeManager.dbJsonType(deployProp, DbPlatformType.JSONB, jsonB.get(0).length());
64+
}
65+
if (typeManager.jsonMarkerAnnotation() != null
66+
&& !deployProp.getMetaAnnotations(typeManager.jsonMarkerAnnotation()).isEmpty()) {
67+
return typeManager.dbJsonType(deployProp, DbPlatformType.JSON, 0);
68+
}
69+
return typeManager.type(deployProp);
70+
71+
72+
}
73+
74+
/**
75+
* Find all annotations on fields and methods.
76+
*/
77+
private Set<Annotation> findMetaAnnotations(Class<?> dtoType, Method writeMethod, String name, Set<Class<?>> annotationFilter) {
78+
Field field = findField(dtoType, name);
79+
if (field != null) {
80+
Set<Annotation> metaAnnotations = AnnotationUtil.metaFindAllFor(field, annotationFilter);
81+
metaAnnotations.addAll(AnnotationUtil.metaFindAllFor(writeMethod, annotationFilter));
82+
return metaAnnotations;
83+
} else {
84+
return AnnotationUtil.metaFindAllFor(writeMethod, annotationFilter);
85+
}
86+
}
87+
88+
/**
89+
* Find field in class with same name
90+
*/
91+
private Field findField(Class<?> type, String name) {
92+
while (type != Object.class && type != null) {
93+
try {
94+
return dtoType.getDeclaredField(name);
95+
} catch (NoSuchFieldException e) {
96+
type = type.getSuperclass();
97+
}
98+
}
99+
return null;
100+
}
101+
35102
private static MethodHandle lookupMethodHandle(Class<?> dtoType, Method method) throws NoSuchMethodException, IllegalAccessException {
36103
return LOOKUP.findVirtual(dtoType, method.getName(), MethodType.methodType(method.getReturnType(), method.getParameterTypes()));
37104
}

0 commit comments

Comments
 (0)