Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FEATURE: DbJson Support for Dto-Queries #3143

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
* Description of a property of a bean. Includes its deployment information such
* as database column mapping information.
*/
public class DeployBeanProperty {
public class DeployBeanProperty implements DeployProperty {

private static final int ID_ORDER = 1000000;
private static final int UNIDIRECTIONAL_ORDER = 100000;
Expand Down Expand Up @@ -229,6 +229,11 @@ public DeployBeanDescriptor<?> getDesc() {
return desc;
}

@Override
public Class<?> getOwnerType() {
return desc.getBeanType();
}

/**
* Return the DB column length for character columns.
* <p>
Expand Down Expand Up @@ -261,10 +266,12 @@ public void setJsonDeserialize(boolean jsonDeserialize) {
this.jsonDeserialize = jsonDeserialize;
}

@Override
public MutationDetection getMutationDetection() {
return mutationDetection;
}

@Override
public void setMutationDetection(MutationDetection dirtyDetection) {
this.mutationDetection = dirtyDetection;
}
Expand Down Expand Up @@ -479,8 +486,9 @@ public void setGeneratedProperty(GeneratedProperty generatedValue) {
}

/**
* Return true if this property is mandatory.
* Return true if this property is not mandatory.
*/
@Override
public boolean isNullable() {
return nullable;
}
Expand Down Expand Up @@ -851,6 +859,7 @@ public Class<?> getPropertyType() {
/**
* Return the generic type for this property.
*/
@Override
public Type getGenericType() {
return genericType;
}
Expand Down Expand Up @@ -1055,6 +1064,7 @@ public <A extends Annotation> A getMetaAnnotation(Class<A> annotationType) {
return null;
}

@Override
@SuppressWarnings("unchecked")
public <A extends Annotation> List<A> getMetaAnnotations(Class<A> annotationType) {
List<A> result = new ArrayList<>();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package io.ebeaninternal.server.deploy.meta;

import io.ebean.annotation.MutationDetection;

import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.util.List;

/**
* Property, with basic type information (BeanProperty and DtoProperty).
*/
public interface DeployProperty {

/**
* Return the name of the property.
*/
String getName();

/**
* Return the generic type for this property.
*/
Type getGenericType();

/**
* Return the property type.
*/
Class<?> getPropertyType();

/**
* Returns the owner class of this property.
*/
Class<?> getOwnerType();

/**
* Returns the annotations on this property.
*/
<A extends Annotation> List<A> getMetaAnnotations(Class<A> annotationType);

/**
* Returns the mutation detection setting of this property.
*/
MutationDetection getMutationDetection();

/**
* Sets the mutation detection setting of this property.
*/
void setMutationDetection(MutationDetection mutationDetection);

/**
* Return true if this property is not mandatory.
*/
boolean isNullable();
}
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ private void setDbJsonType(DeployBeanProperty prop, int dbType, int dbLength, Mu
/**
* Return the JDBC type for the JSON storage type.
*/
private int dbJsonStorage(DbJsonType dbJsonType) {
public static int dbJsonStorage(DbJsonType dbJsonType) {
switch (dbJsonType) {
case JSONB:
return DbPlatformType.JSONB;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package io.ebeaninternal.server.dto;

import io.ebean.annotation.DbJson;
import io.ebean.annotation.DbJsonB;
import io.ebeaninternal.api.CoreLog;
import io.ebeaninternal.server.type.TypeManager;

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

DtoMetaBuilder(Class<?> dtoType, TypeManager typeManager) {
this.dtoType = dtoType;
this.typeManager = typeManager;
annotationFilter.add(DbJson.class);
annotationFilter.add(DbJsonB.class);
if (typeManager.jsonMarkerAnnotation() != null) {
annotationFilter.add(typeManager.jsonMarkerAnnotation());
}
}

DtoMeta build() {
Expand All @@ -38,7 +46,7 @@ private void readProperties() {
if (includeMethod(method)) {
try {
final String name = propertyName(method.getName());
properties.add(new DtoMetaProperty(typeManager, dtoType, method, name));
properties.add(new DtoMetaProperty(typeManager, dtoType, method, name, annotationFilter));
} catch (Exception e) {
CoreLog.log.log(DEBUG, "exclude on " + dtoType + " method " + method, e);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package io.ebeaninternal.server.dto;

import io.ebean.annotation.MutationDetection;
import io.ebeaninternal.server.deploy.meta.DeployProperty;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

/**
* DeployProperty for Dto-Properties.
*
* @author Roland Praml, FOCONIS AG
*/
class DtoMetaDeployProperty implements DeployProperty {
private final String name;
private final Class<?> ownerType;
private final Type genericType;
private final Class<?> propertyType;
private final Set<Annotation> metaAnnotations;
private final boolean nullable;
private MutationDetection mutationDetection = MutationDetection.DEFAULT;

DtoMetaDeployProperty(String name, Class<?> ownerType, Type genericType, Class<?> propertyType, Set<Annotation> metaAnnotations, Method method) {
this.name = name;
this.ownerType = ownerType;
this.genericType = genericType;
this.nullable = !propertyType.isPrimitive();
this.propertyType = propertyType;
this.metaAnnotations = metaAnnotations;
}

@Override
public String getName() {
return name;
}

@Override
public Type getGenericType() {
return genericType;
}

@Override
public Class<?> getPropertyType() {
return propertyType;
}

@Override
public Class<?> getOwnerType() {
return ownerType;
}

@Override
public <A extends Annotation> List<A> getMetaAnnotations(Class<A> annotationType) {
List<A> result = new ArrayList<>();
for (Annotation ann : metaAnnotations) {
if (ann.annotationType() == annotationType) {
result.add((A) ann);
}
}
return result;
}

@Override
public MutationDetection getMutationDetection() {
return mutationDetection;
}

@Override
public void setMutationDetection(MutationDetection mutationDetection) {
this.mutationDetection = mutationDetection;
}

@Override
public boolean isNullable() {
return nullable;
}
}
Original file line number Diff line number Diff line change
@@ -1,15 +1,26 @@
package io.ebeaninternal.server.dto;

import io.ebean.annotation.DbJson;
import io.ebean.annotation.DbJsonB;
import io.ebean.config.dbplatform.DbPlatformType;
import io.ebean.core.type.DataReader;
import io.ebean.core.type.ScalarType;
import io.ebean.util.AnnotationUtil;
import io.ebeaninternal.server.deploy.meta.DeployProperty;
import io.ebeaninternal.server.deploy.parse.DeployUtil;
import io.ebeaninternal.server.type.TypeManager;

import java.lang.annotation.Annotation;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.sql.SQLException;
import java.util.Collections;
import java.util.List;
import java.util.Set;

final class DtoMetaProperty implements DtoReadSet {

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

DtoMetaProperty(TypeManager typeManager, Class<?> dtoType, Method writeMethod, String name) throws IllegalAccessException, NoSuchMethodException {
DtoMetaProperty(TypeManager typeManager, Class<?> dtoType, Method writeMethod, String name, Set<Class<?>> annotationFilter)
throws IllegalAccessException, NoSuchMethodException {
this.dtoType = dtoType;
this.name = name;
if (writeMethod != null) {
this.setter = lookupMethodHandle(dtoType, writeMethod);
this.scalarType = typeManager.type(propertyType(writeMethod), propertyClass(writeMethod));
Field field = findField(dtoType, name);
DeployProperty deployProp = new DtoMetaDeployProperty(name,
dtoType,
propertyType(writeMethod),
propertyClass(writeMethod),
field == null ? Collections.emptySet() : AnnotationUtil.metaFindAllFor(field, annotationFilter),
writeMethod);
scalarType = getScalarType(typeManager, deployProp);
} else {
this.scalarType = null;
this.setter = null;
}
}

private ScalarType<?> getScalarType(TypeManager typeManager, DeployProperty deployProp) {
final ScalarType<?> scalarType;

List<DbJson> json = deployProp.getMetaAnnotations(DbJson.class);
if (!json.isEmpty()) {
return typeManager.dbJsonType(deployProp, DeployUtil.dbJsonStorage(json.get(0).storage()), json.get(0).length());
}
List<DbJsonB> jsonB = deployProp.getMetaAnnotations(DbJsonB.class);
if (!jsonB.isEmpty()) {
return typeManager.dbJsonType(deployProp, DbPlatformType.JSONB, jsonB.get(0).length());
}
if (typeManager.jsonMarkerAnnotation() != null
&& !deployProp.getMetaAnnotations(typeManager.jsonMarkerAnnotation()).isEmpty()) {
return typeManager.dbJsonType(deployProp, DbPlatformType.JSON, 0);
}
return typeManager.type(deployProp);


}

/**
* Find all annotations on fields and methods.
*/
private Set<Annotation> findMetaAnnotations(Class<?> dtoType, Method writeMethod, String name, Set<Class<?>> annotationFilter) {
Field field = findField(dtoType, name);
if (field != null) {
Set<Annotation> metaAnnotations = AnnotationUtil.metaFindAllFor(field, annotationFilter);
metaAnnotations.addAll(AnnotationUtil.metaFindAllFor(writeMethod, annotationFilter));
return metaAnnotations;
} else {
return AnnotationUtil.metaFindAllFor(writeMethod, annotationFilter);
}
}

/**
* Find field in class with same name
*/
private Field findField(Class<?> type, String name) {
while (type != Object.class && type != null) {
try {
return dtoType.getDeclaredField(name);
} catch (NoSuchFieldException e) {
type = type.getSuperclass();
}
}
return null;
}

private static MethodHandle lookupMethodHandle(Class<?> dtoType, Method method) throws NoSuchMethodException, IllegalAccessException {
return LOOKUP.findVirtual(dtoType, method.getName(), MethodType.methodType(method.getReturnType(), method.getParameterTypes()));
}
Expand Down
Loading