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

com.vonage.client.Jsonable Maven / Gradle / Ivy

/*
 *   Copyright 2024 Vonage
 *
 *   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.vonage.client;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;

/**
 * Indicates that a class can be serialized to and parsed from JSON.
 *
 * @since 7.7.0
 */
public interface Jsonable {

	/**
	 * Convenience method for creating an ObjectMapper with standard settings.
	 *
	 * @return A new ObjectMapper with appropriate configuration.
	 */
	static ObjectMapper createDefaultObjectMapper() {
		return new ObjectMapper()
				.registerModule(new JavaTimeModule())
				.setSerializationInclusion(JsonInclude.Include.NON_NULL)
				.configure(DeserializationFeature.FAIL_ON_IGNORED_PROPERTIES, false)
				.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
				.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
	}

	/**
	 * Serialises this class to a JSON payload.
	 *
	 * @return The JSON string representing this class's marked properties.
	 */
	default String toJson() {
		try {
			ObjectMapper mapper = this instanceof JsonableBaseObject ?
					((JsonableBaseObject) this).createJsonObjectMapper() : createDefaultObjectMapper();

			return mapper.writeValueAsString(this);
		}
		catch (JsonProcessingException jpe) {
			throw new VonageUnexpectedException("Failed to produce JSON from "+getClass().getSimpleName()+" object.", jpe);
		}
	}

	/**
	 * Updates this class's fields from the JSON payload.
	 *
	 * @param json The JSON string.
	 *
	 * @throws VonageResponseParseException If the JSON was invalid or this class couldn't be updated.
	 */
	default void updateFromJson(String json) {
		if (json == null || json.trim().isEmpty()) return;
		try {
			ObjectMapper mapper = this instanceof JsonableBaseObject ?
					((JsonableBaseObject) this).createJsonObjectMapper() : createDefaultObjectMapper();

			mapper.readerForUpdating(this).readValue(json);
		}
		catch (IOException ex) {
			throw new VonageResponseParseException("Failed to produce "+getClass().getSimpleName()+" from JSON.", ex);
		}
	}

	/**
	 * Delegates to {@linkplain #fromJson(String, Class)}, using the type varargs for inferring the class.
	 *
	 * @param json The JSON string to parse.
	 * @param type Unused. This is a hack to get the array class's component type.
	 *
	 * @return A new instance of the inferred Jsonable.
	 *
	 * @param  A class which implements this interface.
	 *
	 * @throws VonageUnexpectedException If a no-args constructor for the class was not found.
	 * @throws VonageResponseParseException If the JSON was invalid or this class couldn't be updated.
	 */
	@SuppressWarnings("unchecked")
	static  J fromJson(String json, J... type) {
		return fromJson(json, (Class) type.getClass().getComponentType());
	}

	/**
	 * Creates a new instance of the designated Jsonable class, calling its no-args constructor
	 * followed by {@link #updateFromJson(String)}.
	 *
	 * @param json The JSON string to parse.
	 * @param jsonable The Jsonable class to construct.
	 *
	 * @return A new instance of the Jsonable class.
	 *
	 * @param  A class which implements this interface.
	 *
	 * @throws VonageUnexpectedException If a no-args constructor for the class was not found.
	 * @throws VonageResponseParseException If the JSON was invalid or this class couldn't be updated.
	 */
	static  J fromJson(String json, Class jsonable) {
		try {
			if (Modifier.isAbstract(jsonable.getModifiers())) {
				return createDefaultObjectMapper().readValue(json, jsonable);
			}
			Constructor constructor = jsonable.getDeclaredConstructor();
			if (!(constructor.isAccessible())) {
				constructor.setAccessible(true);
			}
			J instance = constructor.newInstance();
			instance.updateFromJson(json);
			return instance;
		}
		catch (ReflectiveOperationException | JsonProcessingException ex) {
			throw new VonageUnexpectedException(ex);
		}
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy