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

com.tinypass.client.common.JacksonJsonParser Maven / Gradle / Ivy

There is a newer version: 16.366.0
Show newest version
package com.tinypass.client.common;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.module.SimpleModule;

import java.io.IOException;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * Created  by alexander vorozhtsov on 17.09.14.
 *
 * Json parser based on Jackson
 *
 */
public class JacksonJsonParser extends JsonParser {

	public static ObjectMapper mapper;

	static {
		mapper = new ObjectMapper();
		mapper.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE);
		mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
        mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
		SimpleModule module = new SimpleModule();
		module.addSerializer(Date.class, new EpochDateSerializer());
		module.addDeserializer(Date.class, new EpochDateDeserializer());
		mapper.registerModule(module);
	}

	public final static class EpochDateSerializer extends JsonSerializer {

		@Override
		public void serialize(Date value, JsonGenerator jgen, SerializerProvider provider) throws IOException {
			jgen.writeNumber(value.getTime() / 1000L);
		}
	}

	public final static class EpochDateDeserializer extends JsonDeserializer {

		@Override
		public Date deserialize(com.fasterxml.jackson.core.JsonParser jp, DeserializationContext ctxt)
				throws IOException {
			return new Date(jp.getNumberValue().longValue() * 1000L);
		}
	}

	@Override
	@SuppressWarnings("unchecked")
	public  T deserialize(String json, Class cls) throws IOException {
		return (T) mapper.readValue(json, cls);
	}

	@Override
	@SuppressWarnings("unchecked")
	public  T deserialize(String json, String containerType, Class cls) throws ApiException {
		if (json == null)
			return null;

		Map m;
		try {
			// the response is always an envelope.
			m = mapper.readValue(json, Map.class);
		} catch (IOException e) {
			throw new ApiException(500, "Unable to deserialize JSON: " + e.getMessage());
		}
		// if the error code is != 0 (or it's not present) it's an error
		Integer returnCode = (Integer) m.get("code");
        //if "code" and "data" are empty, so result can be object instance of cls (TokenResponse for example) without wrapping into [Result] - https://tinypass.atlassian.net/browse/ID-590
        if (returnCode == null && m.get("data")== null) {
            try {
                Object value = mapper.readValue(json, cls);
                if (value != null) {
                    return (T)value;
                }
            } catch (IOException e) {
                ;//value not parsed, use old style
            }
        }
		if (returnCode == null || returnCode != 0) {
			ApiException apiException = new ApiException(returnCode == null ? 500 : returnCode,
				(String) m.get("message"));

			if (m.get("validation_errors") != null) {
				Map exceptions = (Map) m.get("validation_errors");
				for (String key : exceptions.keySet()) {

					apiException.addException(new ApiParameterException(key, exceptions.get(key)));
				}
			}

			throw apiException;
		}

		if (containerType == null && cls == null)
			return null;

		Object payload = getPayload(m, cls);
		if (payload == null)
				return null;
//			throw new RuntimeException("Unable to find payload of type " + cls +
//				" while deserializing JSON: " + json);

		Object ret = mapToObject(payload, containerType, cls); // actual mapping from map, list or string to object
		if (ret instanceof List) {
			List l = (List) ret;

			Integer limit = (Integer) m.get("limit");
			Integer offset = (Integer) m.get("offset");
			Integer total = (Integer) m.get("total");
			Integer count = (Integer) m.get("count");

			PageList pageList = new PageList(l);
			pageList.setLimit(limit == null ? 0 : limit);
			pageList.setOffset(offset == null ? 0 : offset);
			pageList.setTotal(total == null ? l.size() : total);
			pageList.setCount(count == null ? l.size() : count);
			return (T) pageList;
		}
		return (T) ret;
	}

	private Object mapToObject(Object payload, String containerType, Class cls) {
		if ("List".equalsIgnoreCase(containerType) || "Array".equalsIgnoreCase(containerType)) {
			JavaType typeInfo = mapper.getTypeFactory().constructCollectionType(List.class, cls);
			return mapper.convertValue(payload, typeInfo);
		} else {
			return mapper.convertValue(payload, cls);
		}
	}

	//OMV3 - full clean required here  TPWEBAPP 1848
	private Object getPayload(Map m, Class cls) {
		if (String.class.equals(cls)) { // string is a special case
			Object ret = m.get("data");
			if (ret instanceof String || ret instanceof List)
				return ret;
			return null;

		} else if (Long.class.equals(cls) || Integer.class.equals(cls) || Double.class.equals(cls) ||
			BigDecimal.class.equals(cls) || Boolean.class.equals(cls)) {
			if (m.get("data") instanceof List)
				return m.get("data");

			return mapper.convertValue(m.get("data"), cls);
		}

		for (Object o : m.values()) {
			if (o instanceof Map) { // generic object
				return o;
			} else if (o instanceof List) { // generic list of objects
				return o;
			}
		}
		return null;
	}

    @Override
    public String serialize(Object obj) throws ApiException {
        try {
            if (obj != null) {
                if (obj instanceof String) {
                    return (String) obj;
                }
                return mapper.writeValueAsString(obj);
            } else {
                return null;
            }
        } catch (Exception e) {
            throw new ApiException(500, e.getMessage());
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy