/*
 * Copyright 2017-2020 original authors
 *
 * 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
 *
 * https://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 io.micronaut.jackson;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.deser.BeanDeserializerModifier;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.BeanSerializerModifier;
import io.micronaut.context.annotation.*;
import io.micronaut.core.reflect.GenericTypeUtils;

import edu.umd.cs.findbugs.annotations.Nullable;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import java.text.SimpleDateFormat;
import java.util.Locale;
import java.util.Optional;
import java.util.TimeZone;

Factory bean for creating the Jackson ObjectMapper.
Author:Graeme Rocher
Since:1.0
/** * Factory bean for creating the Jackson {@link com.fasterxml.jackson.databind.ObjectMapper}. * * @author Graeme Rocher * @since 1.0 */
@Factory @BootstrapContextCompatible public class ObjectMapperFactory {
Name for Micronaut module.
/** * Name for Micronaut module. */
public static final String MICRONAUT_MODULE = "micronaut"; @Inject // have to be fully qualified due to JDK Module type protected com.fasterxml.jackson.databind.Module[] jacksonModules = new com.fasterxml.jackson.databind.Module[0]; @Inject protected JsonSerializer[] serializers = new JsonSerializer[0]; @Inject protected JsonDeserializer[] deserializers = new JsonDeserializer[0]; @Inject protected BeanSerializerModifier[] beanSerializerModifiers = new BeanSerializerModifier[0]; @Inject protected BeanDeserializerModifier[] beanDeserializerModifiers = new BeanDeserializerModifier[0]; @Inject protected KeyDeserializer[] keyDeserializers = new KeyDeserializer[0];
Builds the core Jackson ObjectMapper from the optional configuration and JsonFactory.
Params:
  • jacksonConfiguration – The configuration
  • jsonFactory – The JSON factory
Returns:The ObjectMapper
/** * Builds the core Jackson {@link ObjectMapper} from the optional configuration and {@link JsonFactory}. * * @param jacksonConfiguration The configuration * @param jsonFactory The JSON factory * @return The {@link ObjectMapper} */
@Singleton @Primary @Named("json") @BootstrapContextCompatible public ObjectMapper objectMapper(@Nullable JacksonConfiguration jacksonConfiguration, @Nullable JsonFactory jsonFactory) { ObjectMapper objectMapper = jsonFactory != null ? new ObjectMapper(jsonFactory) : new ObjectMapper(); final boolean hasConfiguration = jacksonConfiguration != null; if (!hasConfiguration || jacksonConfiguration.isModuleScan()) { objectMapper.findAndRegisterModules(); } objectMapper.registerModules(jacksonModules); SimpleModule module = new SimpleModule(MICRONAUT_MODULE); for (JsonSerializer serializer : serializers) { Class<? extends JsonSerializer> type = serializer.getClass(); Type annotation = type.getAnnotation(Type.class); if (annotation != null) { Class[] value = annotation.value(); for (Class aClass : value) { module.addSerializer(aClass, serializer); } } else { Optional<Class> targetType = GenericTypeUtils.resolveSuperGenericTypeArgument(type); if (targetType.isPresent()) { module.addSerializer(targetType.get(), serializer); } else { module.addSerializer(serializer); } } } for (JsonDeserializer deserializer : deserializers) { Class<? extends JsonDeserializer> type = deserializer.getClass(); Type annotation = type.getAnnotation(Type.class); if (annotation != null) { Class[] value = annotation.value(); for (Class aClass : value) { module.addDeserializer(aClass, deserializer); } } else { Optional<Class> targetType = GenericTypeUtils.resolveSuperGenericTypeArgument(type); targetType.ifPresent(aClass -> module.addDeserializer(aClass, deserializer)); } } for (KeyDeserializer keyDeserializer : keyDeserializers) { Class<? extends KeyDeserializer> type = keyDeserializer.getClass(); Type annotation = type.getAnnotation(Type.class); if (annotation != null) { Class[] value = annotation.value(); for (Class clazz : value) { module.addKeyDeserializer(clazz, keyDeserializer); } } } objectMapper.registerModule(module); for (BeanSerializerModifier beanSerializerModifier : beanSerializerModifiers) { objectMapper.setSerializerFactory( objectMapper.getSerializerFactory().withSerializerModifier( beanSerializerModifier )); } objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); objectMapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true); objectMapper.configure(DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS, true); if (hasConfiguration) { ObjectMapper.DefaultTyping defaultTyping = jacksonConfiguration.getDefaultTyping(); if (defaultTyping != null) { objectMapper.activateDefaultTyping(objectMapper.getPolymorphicTypeValidator(), defaultTyping); } JsonInclude.Include include = jacksonConfiguration.getSerializationInclusion(); if (include != null) { objectMapper.setSerializationInclusion(include); } String dateFormat = jacksonConfiguration.getDateFormat(); if (dateFormat != null) { objectMapper.setDateFormat(new SimpleDateFormat(dateFormat)); } Locale locale = jacksonConfiguration.getLocale(); if (locale != null) { objectMapper.setLocale(locale); } TimeZone timeZone = jacksonConfiguration.getTimeZone(); if (timeZone != null) { objectMapper.setTimeZone(timeZone); } PropertyNamingStrategy propertyNamingStrategy = jacksonConfiguration.getPropertyNamingStrategy(); if (propertyNamingStrategy != null) { objectMapper.setPropertyNamingStrategy(propertyNamingStrategy); } jacksonConfiguration.getSerializationSettings().forEach(objectMapper::configure); jacksonConfiguration.getDeserializationSettings().forEach(objectMapper::configure); jacksonConfiguration.getMapperSettings().forEach(objectMapper::configure); jacksonConfiguration.getParserSettings().forEach(objectMapper::configure); jacksonConfiguration.getGeneratorSettings().forEach(objectMapper::configure); } return objectMapper; } }