/*
* Copyright 2011 VZ Netzwerke Ltd
* Copyright 2014 devbliss GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.mongojack.internal.util;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationConfig;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.BeanPropertyWriter;
import com.fasterxml.jackson.databind.ser.DefaultSerializerProvider;
import com.fasterxml.jackson.databind.ser.SerializerFactory;
import com.fasterxml.jackson.databind.ser.std.BeanSerializerBase;
/**
* Accesses things in Jackson that usually aren't accessible. Here be dragons.
*/
public class JacksonAccessor {
public static JsonDeserializer findDeserializer(ObjectMapper objectMapper,
JavaType type) {
return invoke(objectMapper, objectMapperFindRootDeserializer,
JsonDeserializer.class,
createDeserializationContext(objectMapper), type);
}
public static DeserializationContext createDeserializationContext(
ObjectMapper objectMapper) {
return invoke(objectMapper, objectMapperCreateDeserializationContext,
DeserializationContext.class, null,
objectMapper.getDeserializationConfig());
}
public static BeanPropertyWriter findPropertyWriter(
BeanSerializerBase serializer, String propertyName) {
BeanPropertyWriter[] props = get(serializer, beanSerializerBaseProps,
BeanPropertyWriter[].class);
for (BeanPropertyWriter prop : props) {
if (propertyName.equals(prop.getName())) {
return prop;
}
}
return null;
}
public static SerializerFactory getSerializerFactory(
ObjectMapper objectMapper) {
return get(objectMapper, objectMapperSerializerFactory,
SerializerFactory.class);
}
public static SerializerProvider getSerializerProvider(
ObjectMapper objectMapper) {
DefaultSerializerProvider serializerProvider = (DefaultSerializerProvider) objectMapper
.getSerializerProvider();
return serializerProvider.createInstance(
objectMapper.getSerializationConfig(),
getSerializerFactory(objectMapper));
}
public static JsonSerializer findValueSerializer(
SerializerProvider serializerProvider, JavaType javaType) {
try {
return serializerProvider.findValueSerializer(javaType, null);
} catch (JsonMappingException e) {
throw new RuntimeException(e);
}
}
public static JsonSerializer findValueSerializer(
SerializerProvider serializerProvider, Class clazz) {
try {
return serializerProvider.findValueSerializer(clazz, null);
} catch (JsonMappingException e) {
throw new RuntimeException(e);
}
}
private static final Method objectMapperCreateDeserializationContext;
private static final Method objectMapperFindRootDeserializer;
private static final Field beanSerializerBaseProps;
private static final Field objectMapperSerializerFactory;
static {
objectMapperCreateDeserializationContext = findMethod(
ObjectMapper.class, "createDeserializationContext",
new Class[] {JsonParser.class, DeserializationConfig.class});
objectMapperFindRootDeserializer = findMethod(ObjectMapper.class,
"_findRootDeserializer", new Class[] {
DeserializationContext.class, JavaType.class});
beanSerializerBaseProps = findField(BeanSerializerBase.class, "_props");
objectMapperSerializerFactory = findField(ObjectMapper.class,
"_serializerFactory");
}
private static Method findMethod(Class clazz, String name, Class[] argTypes) {
try {
Method method = clazz.getDeclaredMethod(name, argTypes);
method.setAccessible(true);
return method;
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
}
}
private static Field findField(Class clazz, String name) {
try {
Field field = clazz.getDeclaredField(name);
field.setAccessible(true);
return field;
} catch (NoSuchFieldException e) {
throw new RuntimeException(e);
}
}
private static <T> T get(Object object, Field field, Class<T> type) {
try {
return (T) field.get(object);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
private static <T> T invoke(Object object, Method method,
Class<T> returnType, Object... args) {
try {
return (T) method.invoke(object, args);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
}
}
}