All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.wavemaker.runtime.commons.WMObjectMapper Maven / Gradle / Ivy

There is a newer version: 11.9.2
Show newest version
/*******************************************************************************
 * Copyright (C) 2022-2023 WaveMaker, Inc.
 *
 * 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 com.wavemaker.runtime.commons;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Reader;
import java.io.StringWriter;
import java.io.Writer;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.util.Date;

import org.apache.commons.io.IOUtils;
import org.springframework.data.domain.Slice;
import org.springframework.http.HttpHeaders;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.TreeNode;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.Module;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectReader;
import com.fasterxml.jackson.databind.ObjectWriter;
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.cfg.MapperConfig;
import com.fasterxml.jackson.databind.introspect.AnnotatedMethod;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.FilterProvider;
import com.fasterxml.jackson.databind.ser.std.SqlDateSerializer;
import com.fasterxml.jackson.databind.type.TypeFactory;
import com.fasterxml.jackson.datatype.hibernate5.jakarta.Hibernate5JakartaModule;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.wavemaker.commons.json.deserializer.HttpHeadersDeSerializer;
import com.wavemaker.commons.json.deserializer.WMDateDeSerializer;
import com.wavemaker.commons.json.deserializer.WMSqlDateDeSerializer;
import com.wavemaker.commons.json.module.WMJacksonModule;
import com.wavemaker.commons.json.serializer.NoOpByteArraySerializer;
import com.wavemaker.commons.json.serializer.WMLocalDateTimeSerializer;
import com.wavemaker.runtime.commons.mixins.SliceMixin;

public class WMObjectMapper extends ObjectMapper {

    private static final WMObjectMapper INSTANCE = new WMObjectMapper();
    private static final WMPropertyNamingStrategy PROPERTY_NAMING_STRATEGY = new WMPropertyNamingStrategy();

    private WMObjectReadMapper readMapper;
    private WMObjectWriteMapper writeMapper;

    protected WMObjectMapper() {
        readMapper = new WMObjectReadMapper();
        writeMapper = new WMObjectWriteMapper();
    }

    public static WMObjectMapper getInstance() {
        return INSTANCE;
    }

    /**
     * Method that can be used to serialize any Java value as
     * JSON output, written to File provided.
     */
    @Override
    public void writeValue(File resultFile, Object value)
        throws IOException {
        writeMapper.writeValue(resultFile, value);
    }

    @Override
    public void writeValue(OutputStream out, Object value)
        throws IOException {
        writeMapper.writeValue(out, value);
    }

    @Override
    public void writeValue(Writer w, Object value)
        throws IOException {
        writeMapper.writeValue(w, value);
    }

    @Override
    public String writeValueAsString(Object value)
        throws JsonProcessingException {
        return writeMapper.writeValueAsString(value);
    }

    @Override
    public byte[] writeValueAsBytes(Object value)
        throws JsonProcessingException {
        return writeMapper.writeValueAsBytes(value);
    }

    @Override
    public void writeTree(JsonGenerator jgen, TreeNode rootNode) throws IOException {
        writeMapper.writeTree(jgen, rootNode);
    }

    @Override
    public void writeValue(JsonGenerator jgen, Object value) throws IOException {
        writeMapper.writeValue(jgen, value);
    }

    @Override
    public void writeTree(JsonGenerator jgen, JsonNode rootNode) throws IOException {
        writeMapper.writeValue(jgen, rootNode);
    }

    @Override
    public ObjectWriter writer() {
        return writeMapper.writer();
    }

    @Override
    public ObjectWriter writerWithView(final Class serializationView) {
        return writeMapper.writerWithView(serializationView);
    }

    @Override
    public ObjectWriter writer(final FilterProvider filterProvider) {
        return writeMapper.writer(filterProvider);
    }

    @Override
    public  T readValue(File src, Class valueType)
        throws IOException {
        return readMapper.readValue(src, valueType);
    }

    @Override
    public  T readValue(File src, TypeReference valueTypeRef)
        throws IOException {
        return readMapper.readValue(src, valueTypeRef);
    }

    @Override
    public  T readValue(File src, JavaType valueType)
        throws IOException {
        return readMapper.readValue(src, valueType);
    }

    @Override
    public  T readValue(URL src, Class valueType)
        throws IOException {

        return readMapper.readValue(src, valueType);
    }

    @Override
    public  T readValue(URL src, TypeReference valueTypeRef)
        throws IOException {
        return readMapper.readValue(src, valueTypeRef);
    }

    @Override
    public  T readValue(URL src, JavaType valueType)
        throws IOException {
        return readMapper.readValue(src, valueType);
    }

    @Override
    public  T readValue(String content, Class valueType) throws JsonProcessingException {
        return readMapper.readValue(content, valueType);
    }

    @Override
    public  T readValue(String content, TypeReference valueTypeRef) throws JsonProcessingException {
        return readMapper.readValue(content, valueTypeRef);
    }

    @Override
    public  T readValue(String content, JavaType valueType) throws JsonProcessingException {
        return readMapper.readValue(content, valueType);
    }

    @Override
    public  T readValue(Reader src, Class valueType)
        throws IOException {
        return readMapper.readValue(src, valueType);
    }

    @Override
    public  T readValue(Reader src, TypeReference valueTypeRef)
        throws IOException {
        return readMapper.readValue(src, valueTypeRef);
    }

    @Override
    public  T readValue(Reader src, JavaType valueType)
        throws IOException {
        return readMapper.readValue(src, valueType);
    }

    @Override
    public  T readValue(InputStream src, Class valueType)
        throws IOException {
        return readMapper.readValue(src, valueType);
    }

    @Override
    public  T readValue(InputStream src, TypeReference valueTypeRef)
        throws IOException {
        return readMapper.readValue(src, valueTypeRef);
    }

    @Override
    public  T readValue(byte[] src, Class valueType)
        throws IOException {
        return readMapper.readValue(src, valueType);
    }

    @Override
    public  T readValue(
        byte[] src, int offset, int len,
        Class valueType)
        throws IOException {
        return readMapper.readValue(src, offset, len, valueType);
    }

    @Override
    public  T readValue(byte[] src, TypeReference valueTypeRef)
        throws IOException {
        return readMapper.readValue(src, valueTypeRef);
    }

    @Override
    public  T readValue(
        byte[] src, int offset, int len,
        TypeReference valueTypeRef)
        throws IOException {
        return readMapper.readValue(src, offset, len, valueTypeRef);
    }

    @Override
    public  T readValue(byte[] src, JavaType valueType)
        throws IOException {
        return readMapper.readValue(src, valueType);
    }

    @Override
    public  T readValue(
        byte[] src, int offset, int len,
        JavaType valueType)
        throws IOException {
        return readMapper.readValue(src, offset, len, valueType);
    }

    @Override
    public  T readValue(InputStream src, JavaType valueType) throws IOException {
        if (String.class.equals(valueType.getRawClass())) {
            StringWriter stringWriter = new StringWriter();
            IOUtils.copy(src, stringWriter, StandardCharsets.UTF_8);
            return (T) stringWriter.toString();
        }
        return readMapper.readValue(src, valueType);
    }

    @Override
    public ObjectWriter writerWithDefaultPrettyPrinter() {
        return writeMapper.writerWithDefaultPrettyPrinter();
    }

    @Override
    public ObjectReader reader() {
        return readMapper.reader();
    }

    public void registerReaderModule(final Module mapperModule) {
        readMapper.registerModule(mapperModule);
    }

    public void registerWriteModule(final Module mapperModule) {
        writeMapper.registerModule(mapperModule);
    }

    private static class WMObjectReadMapper extends ObjectMapper {

        WMObjectReadMapper() {
            setTypeFactory(TypeFactory.defaultInstance().withClassLoader(WMObjectReadMapper.class.getClassLoader()));
            configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
            SimpleModule module = new SimpleModule("WMDefaultDeSerializer");

            module.addDeserializer(Date.class, new WMDateDeSerializer());
            module.addDeserializer(java.sql.Date.class, new WMSqlDateDeSerializer());
            module.addDeserializer(HttpHeaders.class, new HttpHeadersDeSerializer());
            registerModule(module);

            JavaTimeModule javaTimeModule = new JavaTimeModule();
            registerModule(javaTimeModule);

            setPropertyNamingStrategy(PROPERTY_NAMING_STRATEGY);
        }
    }

    private static class WMObjectWriteMapper extends ObjectMapper {

        WMObjectWriteMapper() {
            setTypeFactory(TypeFactory.defaultInstance().withClassLoader(WMObjectWriteMapper.class.getClassLoader()));
            disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
            configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
            // we are handling self references using @JsonIgnoreProperties
            configure(SerializationFeature.FAIL_ON_SELF_REFERENCES, false);
            setConfig(getSerializationConfig().withView(Object.class));

            // mixing to ignore pageable field from page response.
            addMixIn(Slice.class, SliceMixin.class);

            Hibernate5JakartaModule hibernate5JakartaModule = new Hibernate5JakartaModule();
            hibernate5JakartaModule.disable(Hibernate5JakartaModule.Feature.FORCE_LAZY_LOADING);
            registerModule(hibernate5JakartaModule);

            SimpleModule module = new SimpleModule("WMDefaultSerializer");
            module.addSerializer(byte[].class, new NoOpByteArraySerializer());
//            module.addSerializer(Sort.class, new SortJsonSerializer());
            registerModule(module);

            JavaTimeModule javaTimeModule = new JavaTimeModule();
            javaTimeModule.addSerializer(LocalDateTime.class, new WMLocalDateTimeSerializer());
            registerModule(javaTimeModule);

            registerModule(new WMJacksonModule(false));

            SimpleModule dateModule = new SimpleModule();
            dateModule.addSerializer(java.sql.Date.class,
                new SqlDateSerializer().withFormat(false, new SimpleDateFormat("yyyy-MM-dd")));

            registerModule(dateModule);

            setPropertyNamingStrategy(PROPERTY_NAMING_STRATEGY);
        }
    }

    private static class WMPropertyNamingStrategy extends PropertyNamingStrategy {

        private static final String[] POSSIBLE_GET_METHOD_START_NAMES = {"get", "is"};
        private static final String[] POSSIBLE_SET_METHOD_START_NAMES = {"set"};

        @Override
        public String nameForGetterMethod(MapperConfig config, AnnotatedMethod method, String defaultName) {
            return getPossibleFieldName(method, defaultName, POSSIBLE_GET_METHOD_START_NAMES);
        }

        @Override
        public String nameForSetterMethod(MapperConfig config, AnnotatedMethod method, String defaultName) {
            return getPossibleFieldName(method, defaultName, POSSIBLE_SET_METHOD_START_NAMES);
        }

        private String getPossibleFieldName(
            AnnotatedMethod method, String defaultName, String[] possibleMethodStartNames) {
            String name = method.getName();
            for (String possibleStartName : possibleMethodStartNames) {
                if (name.startsWith(possibleStartName)) {
                    String remPart = name.substring(possibleStartName.length());
                    if (remPart.isEmpty()) {
                        break;
                    }
                    char upper = remPart.charAt(0);
                    char lower = Character.toLowerCase(upper);
                    if (lower == upper) {
                        break;
                    }
                    StringBuilder sb = new StringBuilder(remPart);
                    sb.setCharAt(0, lower);
                    return sb.toString();
                }
            }
            return defaultName;
        }
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy