mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
Merge branch 'master' of github.com:ebean-orm/ebean
This commit is contained in:
@@ -223,6 +223,8 @@ public class DeployBeanDescriptor<T> {
|
||||
|
||||
private short profileId;
|
||||
|
||||
private Object jacksonAnnotatedClass;
|
||||
|
||||
/**
|
||||
* Construct the BeanDescriptor.
|
||||
*/
|
||||
@@ -1238,6 +1240,7 @@ public class DeployBeanDescriptor<T> {
|
||||
this.descriptor = descriptor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDeployWord(String expression) {
|
||||
return descriptor.getDeployWord(expression);
|
||||
}
|
||||
@@ -1252,4 +1255,16 @@ public class DeployBeanDescriptor<T> {
|
||||
return (property == null) ? null : "${ta}." + property.getDbColumn();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the jackson annotated class, if jackson is present.
|
||||
*/
|
||||
public Object /*AnnotatedClass*/ getJacksonAnnotatedClass() {
|
||||
if (jacksonAnnotatedClass == null) {
|
||||
com.fasterxml.jackson.databind.ObjectMapper objectMapper = (com.fasterxml.jackson.databind.ObjectMapper) serverConfig.getObjectMapper();
|
||||
com.fasterxml.jackson.databind.JavaType javaType = objectMapper.getTypeFactory().constructType(beanType);
|
||||
jacksonAnnotatedClass = com.fasterxml.jackson.databind.introspect.AnnotatedClassResolver
|
||||
.resolve(objectMapper.getDeserializationConfig(), javaType, objectMapper.getDeserializationConfig());
|
||||
}
|
||||
return jacksonAnnotatedClass;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1124,4 +1124,18 @@ public class DeployBeanProperty {
|
||||
public void setElementProperty() {
|
||||
this.elementProperty = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the jackson annotated field, if jackson is present.
|
||||
*/
|
||||
public Object /*AnnotatedField*/ getJacksonField() {
|
||||
com.fasterxml.jackson.databind.introspect.AnnotatedClass jac =
|
||||
(com.fasterxml.jackson.databind.introspect.AnnotatedClass) getDesc().getJacksonAnnotatedClass();
|
||||
for (com.fasterxml.jackson.databind.introspect.AnnotatedField candidate : jac.fields()) {
|
||||
if (candidate.getName().equals(getName())) {
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -239,10 +239,9 @@ public class DeployUtil {
|
||||
|
||||
private void setDbJsonType(DeployBeanProperty prop, int dbType, int dbLength) {
|
||||
|
||||
Class<?> type = prop.getPropertyType();
|
||||
ScalarType<?> scalarType = typeManager.getJsonScalarType(type, dbType, dbLength, prop.getGenericType());
|
||||
ScalarType<?> scalarType = typeManager.getJsonScalarType(prop, dbType, dbLength);
|
||||
if (scalarType == null) {
|
||||
throw new RuntimeException("No ScalarType for JSON type [" + type + "] [" + dbType + "]");
|
||||
throw new RuntimeException("No ScalarType for JSON property [" + prop + "] [" + dbType + "]");
|
||||
}
|
||||
prop.setDbType(dbType);
|
||||
prop.setScalarType(scalarType);
|
||||
|
||||
@@ -2,6 +2,8 @@ package io.ebeaninternal.server.type;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.introspect.AnnotatedField;
|
||||
|
||||
import io.ebean.annotation.DbArray;
|
||||
import io.ebean.annotation.DbEnumType;
|
||||
import io.ebean.annotation.DbEnumValue;
|
||||
@@ -17,6 +19,7 @@ import io.ebean.util.AnnotationUtil;
|
||||
import io.ebeaninternal.api.ExtraTypeFactory;
|
||||
import io.ebeaninternal.dbmigration.DbOffline;
|
||||
import io.ebeaninternal.server.core.bootup.BootupClasses;
|
||||
import io.ebeaninternal.server.deploy.meta.DeployBeanProperty;
|
||||
import io.ebeanservice.docstore.api.mapping.DocPropertyType;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.LocalDate;
|
||||
@@ -379,31 +382,36 @@ public final class DefaultTypeManager implements TypeManager {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScalarType<?> getJsonScalarType(Class<?> type, int dbType, int dbLength, Type genericType) {
|
||||
public ScalarType<?> getJsonScalarType(DeployBeanProperty prop, int dbType, int dbLength) {
|
||||
|
||||
Class<?> type = prop.getPropertyType();
|
||||
Type genericType = prop.getGenericType();
|
||||
|
||||
boolean hasJacksonAnnotations = objectMapperPresent && checkJacksonAnnotations(prop);
|
||||
|
||||
if (type.equals(List.class)) {
|
||||
DocPropertyType docType = getDocType(genericType);
|
||||
if (isValueTypeSimple(genericType)) {
|
||||
if (!hasJacksonAnnotations && isValueTypeSimple(genericType)) {
|
||||
return ScalarTypeJsonList.typeFor(postgres, dbType, docType);
|
||||
} else {
|
||||
return createJsonObjectMapperType(type, genericType, dbType, docType);
|
||||
return createJsonObjectMapperType(prop, dbType, docType);
|
||||
}
|
||||
}
|
||||
|
||||
if (type.equals(Set.class)) {
|
||||
DocPropertyType docType = getDocType(genericType);
|
||||
if (isValueTypeSimple(genericType)) {
|
||||
if (!hasJacksonAnnotations && isValueTypeSimple(genericType)) {
|
||||
return ScalarTypeJsonSet.typeFor(postgres, dbType, docType);
|
||||
} else {
|
||||
return createJsonObjectMapperType(type, genericType, dbType, docType);
|
||||
return createJsonObjectMapperType(prop, dbType, docType);
|
||||
}
|
||||
}
|
||||
|
||||
if (type.equals(Map.class)) {
|
||||
if (isMapValueTypeObject(genericType)) {
|
||||
if (!hasJacksonAnnotations && isMapValueTypeObject(genericType)) {
|
||||
return ScalarTypeJsonMap.typeFor(postgres, dbType);
|
||||
} else {
|
||||
return createJsonObjectMapperType(type, genericType, dbType, DocPropertyType.OBJECT);
|
||||
return createJsonObjectMapperType(prop, dbType, DocPropertyType.OBJECT);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -426,7 +434,15 @@ public final class DefaultTypeManager implements TypeManager {
|
||||
}
|
||||
}
|
||||
|
||||
return createJsonObjectMapperType(type, type, dbType, DocPropertyType.OBJECT);
|
||||
return createJsonObjectMapperType(prop, dbType, DocPropertyType.OBJECT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns TRUE, if there is any jackson annotation on that property. All jackson annotations
|
||||
* are annotated with the @JacksonAnnotation meta annotation. So detection is easy.
|
||||
*/
|
||||
private boolean checkJacksonAnnotations(DeployBeanProperty prop) {
|
||||
return AnnotationUtil.findAnnotation(prop.getField(), com.fasterxml.jackson.annotation.JacksonAnnotation.class) != null;
|
||||
}
|
||||
|
||||
private DocPropertyType getDocType(Type genericType) {
|
||||
@@ -459,11 +475,12 @@ public final class DefaultTypeManager implements TypeManager {
|
||||
return Object.class.equals(typeArgs[1]) || "?".equals(typeArgs[1].toString());
|
||||
}
|
||||
|
||||
private ScalarType<?> createJsonObjectMapperType(Class<?> type, Type genericType, int dbType, DocPropertyType docType) {
|
||||
private ScalarType<?> createJsonObjectMapperType(DeployBeanProperty prop, int dbType, DocPropertyType docType) {
|
||||
Class<?> type = prop.getPropertyType();
|
||||
if (objectMapper == null) {
|
||||
throw new IllegalArgumentException("Type [" + type + "] unsupported for @DbJson mapping - Jackson ObjectMapper not present");
|
||||
}
|
||||
return ScalarTypeJsonObjectMapper.createTypeFor(postgres, type, (ObjectMapper) objectMapper, genericType, dbType, docType);
|
||||
return ScalarTypeJsonObjectMapper.createTypeFor(postgres, (AnnotatedField) prop.getJacksonField(), (ObjectMapper) objectMapper, dbType, docType);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -9,14 +9,19 @@ import io.ebeanservice.docstore.api.mapping.DocPropertyType;
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.AnnotationIntrospector;
|
||||
import com.fasterxml.jackson.databind.DeserializationConfig;
|
||||
import com.fasterxml.jackson.databind.JavaType;
|
||||
import com.fasterxml.jackson.databind.JsonMappingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.ObjectWriter;
|
||||
import com.fasterxml.jackson.databind.SerializationConfig;
|
||||
import com.fasterxml.jackson.databind.introspect.AnnotatedField;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Type;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
import java.util.List;
|
||||
@@ -31,20 +36,21 @@ public class ScalarTypeJsonObjectMapper {
|
||||
/**
|
||||
* Create and return the appropriate ScalarType.
|
||||
*/
|
||||
public static ScalarType<?> createTypeFor(boolean postgres, Class<?> type, ObjectMapper objectMapper,
|
||||
Type genericType, int dbType, DocPropertyType docType) {
|
||||
public static ScalarType<?> createTypeFor(boolean postgres, AnnotatedField field, ObjectMapper objectMapper,
|
||||
int dbType, DocPropertyType docType) {
|
||||
|
||||
Class<?> type = field.getRawType();
|
||||
String pgType = getPostgresType(postgres, dbType);
|
||||
if (Set.class.equals(type)) {
|
||||
return new OmSet(objectMapper, genericType, dbType, pgType, docType);
|
||||
return new OmSet(objectMapper, field, dbType, pgType, docType);
|
||||
}
|
||||
if (List.class.equals(type)) {
|
||||
return new OmList(objectMapper, genericType, dbType, pgType, docType);
|
||||
return new OmList(objectMapper, field, dbType, pgType, docType);
|
||||
}
|
||||
if (Map.class.equals(type)) {
|
||||
return new OmMap(objectMapper, genericType, dbType, pgType);
|
||||
return new OmMap(objectMapper, field, dbType, pgType);
|
||||
}
|
||||
return new GenericObject(objectMapper, genericType, dbType, pgType);
|
||||
return new GenericObject(objectMapper, field, dbType, pgType);
|
||||
}
|
||||
|
||||
private static String getPostgresType(boolean postgres, int dbType) {
|
||||
@@ -64,8 +70,8 @@ public class ScalarTypeJsonObjectMapper {
|
||||
*/
|
||||
private static class GenericObject extends Base<Object> {
|
||||
|
||||
public GenericObject(ObjectMapper objectMapper, Type type, int dbType, String pgType) {
|
||||
super(Object.class, objectMapper, type, dbType, pgType, DocPropertyType.OBJECT);
|
||||
public GenericObject(ObjectMapper objectMapper, AnnotatedField field, int dbType, String pgType) {
|
||||
super(Object.class, objectMapper, field, dbType, pgType, DocPropertyType.OBJECT);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,8 +81,8 @@ public class ScalarTypeJsonObjectMapper {
|
||||
@SuppressWarnings("rawtypes")
|
||||
private static class OmSet extends Base<Set> {
|
||||
|
||||
public OmSet(ObjectMapper objectMapper, Type type, int dbType, String pgType, DocPropertyType docType) {
|
||||
super(Set.class, objectMapper, type, dbType, pgType, docType);
|
||||
public OmSet(ObjectMapper objectMapper, AnnotatedField field, int dbType, String pgType, DocPropertyType docType) {
|
||||
super(Set.class, objectMapper, field, dbType, pgType, docType);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -93,8 +99,8 @@ public class ScalarTypeJsonObjectMapper {
|
||||
@SuppressWarnings("rawtypes")
|
||||
private static class OmList extends Base<List> {
|
||||
|
||||
public OmList(ObjectMapper objectMapper, Type type, int dbType, String pgType, DocPropertyType docType) {
|
||||
super(List.class, objectMapper, type, dbType, pgType, docType);
|
||||
public OmList(ObjectMapper objectMapper, AnnotatedField field, int dbType, String pgType, DocPropertyType docType) {
|
||||
super(List.class, objectMapper, field, dbType, pgType, docType);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -111,8 +117,8 @@ public class ScalarTypeJsonObjectMapper {
|
||||
@SuppressWarnings("rawtypes")
|
||||
private static class OmMap extends Base<Map> {
|
||||
|
||||
public OmMap(ObjectMapper objectMapper, Type type, int dbType, String pgType) {
|
||||
super(Map.class, objectMapper, type, dbType, pgType, DocPropertyType.OBJECT);
|
||||
public OmMap(ObjectMapper objectMapper, AnnotatedField field, int dbType, String pgType) {
|
||||
super(Map.class, objectMapper, field, dbType, pgType, DocPropertyType.OBJECT);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -129,9 +135,11 @@ public class ScalarTypeJsonObjectMapper {
|
||||
*/
|
||||
private static abstract class Base<T> extends ScalarTypeBase<T> {
|
||||
|
||||
private final ObjectMapper objectMapper;
|
||||
private final ObjectWriter objectWriter;
|
||||
|
||||
private final JavaType javaType;
|
||||
private final ObjectMapper objectReader;
|
||||
|
||||
private JavaType deserType;
|
||||
|
||||
private final String pgType;
|
||||
|
||||
@@ -140,12 +148,39 @@ public class ScalarTypeJsonObjectMapper {
|
||||
/**
|
||||
* Construct given the object mapper, property type and DB type for storage.
|
||||
*/
|
||||
public Base(Class<T> cls, ObjectMapper objectMapper, Type type, int dbType, String pgType, DocPropertyType docType) {
|
||||
public Base(Class<T> cls, ObjectMapper objectMapper, AnnotatedField field, int dbType, String pgType, DocPropertyType docType) {
|
||||
super(cls, false, dbType);
|
||||
this.pgType = pgType;
|
||||
this.docType = docType;
|
||||
this.objectMapper = objectMapper;
|
||||
this.javaType = objectMapper.getTypeFactory().constructType(type);
|
||||
this.objectReader = objectMapper;
|
||||
|
||||
JavaType javaType = field.getType();
|
||||
DeserializationConfig deserConfig = objectMapper.getDeserializationConfig();
|
||||
AnnotationIntrospector ai = deserConfig.getAnnotationIntrospector();
|
||||
|
||||
if (ai != null && javaType != null && !javaType.hasRawClass(Object.class)) {
|
||||
try {
|
||||
this.deserType = ai.refineDeserializationType(deserConfig, field, javaType);
|
||||
} catch (JsonMappingException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
} else {
|
||||
this.deserType = javaType;
|
||||
}
|
||||
|
||||
SerializationConfig serConfig = objectMapper.getSerializationConfig();
|
||||
ai = deserConfig.getAnnotationIntrospector();
|
||||
|
||||
if (ai != null && javaType != null && !javaType.hasRawClass(Object.class)) {
|
||||
try {
|
||||
JavaType serType = ai.refineSerializationType(serConfig, field, javaType);
|
||||
this.objectWriter = objectMapper.writerFor(serType);
|
||||
} catch (JsonMappingException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
} else {
|
||||
this.objectWriter = objectMapper.writerFor(javaType);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -171,7 +206,7 @@ public class ScalarTypeJsonObjectMapper {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return objectMapper.readValue(json, javaType);
|
||||
return objectReader.readValue(json, deserType);
|
||||
} catch (IOException e) {
|
||||
throw new SQLException("Unable to convert JSON", e);
|
||||
}
|
||||
@@ -187,7 +222,7 @@ public class ScalarTypeJsonObjectMapper {
|
||||
bind.setNull(Types.VARCHAR); // use varchar, otherwise SqlServer/db2 will fail with 'Invalid JDBC data type 5.001.'
|
||||
} else {
|
||||
try {
|
||||
String json = objectMapper.writeValueAsString(value);
|
||||
String json = objectWriter.writeValueAsString(value);
|
||||
bind.setString(json);
|
||||
} catch (JsonProcessingException e) {
|
||||
throw new SQLException("Unable to create JSON", e);
|
||||
@@ -212,7 +247,7 @@ public class ScalarTypeJsonObjectMapper {
|
||||
@Override
|
||||
public String formatValue(T value) {
|
||||
try {
|
||||
return objectMapper.writeValueAsString(value);
|
||||
return objectWriter.writeValueAsString(value);
|
||||
} catch (JsonProcessingException e) {
|
||||
throw new PersistenceException("Unable to create JSON", e);
|
||||
}
|
||||
@@ -221,7 +256,7 @@ public class ScalarTypeJsonObjectMapper {
|
||||
@Override
|
||||
public T parse(String value) {
|
||||
try {
|
||||
return objectMapper.readValue(value, javaType);
|
||||
return objectReader.readValue(value, deserType);
|
||||
} catch (IOException e) {
|
||||
throw new PersistenceException("Unable to convert JSON", e);
|
||||
}
|
||||
@@ -244,12 +279,12 @@ public class ScalarTypeJsonObjectMapper {
|
||||
|
||||
@Override
|
||||
public T jsonRead(JsonParser parser) throws IOException {
|
||||
return objectMapper.readValue(parser, javaType);
|
||||
return objectReader.readValue(parser, deserType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void jsonWrite(JsonGenerator writer, T value) throws IOException {
|
||||
objectMapper.writeValue(writer, value);
|
||||
objectWriter.writeValue(writer, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package io.ebeaninternal.server.type;
|
||||
|
||||
import io.ebean.annotation.DbArray;
|
||||
import io.ebeaninternal.server.deploy.meta.DeployBeanProperty;
|
||||
|
||||
import javax.persistence.EnumType;
|
||||
import java.lang.reflect.Type;
|
||||
@@ -57,7 +58,7 @@ public interface TypeManager {
|
||||
* Note that type expected to be JsonNode or Map.
|
||||
* </p>
|
||||
*/
|
||||
ScalarType<?> getJsonScalarType(Class<?> type, int dbType, int dbLength, Type genericType);
|
||||
ScalarType<?> getJsonScalarType(DeployBeanProperty prop, int dbType, int dbLength);
|
||||
|
||||
/**
|
||||
* Return the ScalarType used to handle DB ARRAY.
|
||||
|
||||
Reference in New Issue
Block a user