CommandResponseJsonDeserializer.java
/*
* Copyright (c) 2017 Bosch Software Innovations GmbH.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/org/documents/epl-2.0/index.php
*
* Contributors:
* Bosch Software Innovations GmbH - initial contribution
*/
package org.eclipse.ditto.signals.commands.base;
import static org.eclipse.ditto.model.base.common.ConditionChecker.checkNotNull;
import java.text.MessageFormat;
import javax.annotation.concurrent.Immutable;
import org.eclipse.ditto.json.JsonFactory;
import org.eclipse.ditto.json.JsonObject;
import org.eclipse.ditto.json.JsonParseException;
import org.eclipse.ditto.model.base.common.HttpStatusCode;
import org.eclipse.ditto.model.base.exceptions.DittoJsonException;
/**
* This class helps to deserialize JSON to a sub-class of {@link CommandResponse}. Hereby this class extracts the
* values which are common for all command responses. All remaining required values have to be extracted in {@link
* FactoryMethodFunction#create(HttpStatusCode)}. There the actual command response object is
* created, too.
*/
@Immutable
public final class CommandResponseJsonDeserializer<T extends CommandResponse> {
private final JsonObject jsonObject;
private final String expectedCommandResponseType;
/**
* Constructs a new {@code CommandResponseJsonDeserializer} object.
*
* @param type the type of the command response.
* @param jsonObject the JSON object to deserialize.
* @throws NullPointerException if any argument is {@code null}.
*/
public CommandResponseJsonDeserializer(final String type, final JsonObject jsonObject) {
checkNotNull(type, "command response type");
checkNotNull(jsonObject, "JSON object to be deserialized");
this.jsonObject = jsonObject;
expectedCommandResponseType = type;
}
/**
* Constructs a new {@code CommandResponseJsonDeserializer} object.
*
* @param type the type of the target command response of deserialization.
* @param jsonString the JSON string to be deserialized.
* @throws NullPointerException if any argument is {@code null}.
* @throws IllegalArgumentException if {@code jsonString} is empty.
* @throws org.eclipse.ditto.json.JsonParseException if {@code jsonString} does not contain a valid JSON object.
*/
public CommandResponseJsonDeserializer(final String type, final String jsonString) {
this(type, JsonFactory.newObject(jsonString));
}
/**
* Partly deserializes the JSON which was given to this object's constructor. The factory method function which is
* given to this method is responsible for creating the actual {@code CommandResponseType}. This method receives the
* partly deserialized values which can be completed by implementors if further values are required.
*
* @param factoryMethodFunction creates the actual {@code CommandResponseType} object.
* @return the command response.
* @throws NullPointerException if {@code factoryMethodFunction} is {@code null}.
* @throws org.eclipse.ditto.json.JsonParseException if the JSON is invalid or if the command response type differs from the expected one.
*/
public T deserialize(final FactoryMethodFunction<T> factoryMethodFunction) {
checkNotNull(factoryMethodFunction, "method for creating a command response object");
validateCommandResponseType();
final int statusCode = jsonObject.getValueOrThrow(CommandResponse.JsonFields.STATUS);
final HttpStatusCode httpStatusCode = HttpStatusCode.forInt(statusCode).orElseThrow(() -> {
final String msgPattern = "HTTP status code <{0}> of JSON Object is not supported!";
return new JsonParseException(MessageFormat.format(msgPattern, statusCode));
});
return factoryMethodFunction.create(httpStatusCode);
}
private void validateCommandResponseType() {
final String actualCommandResponseType = jsonObject.getValueOrThrow(CommandResponse.JsonFields.TYPE);
if (!expectedCommandResponseType.equals(actualCommandResponseType)) {
final String msgPattern = "Command Response JSON was not a <{0}> command response but a <{1}>!";
final String msg = MessageFormat.format(msgPattern, expectedCommandResponseType, actualCommandResponseType);
throw new DittoJsonException(new JsonParseException(msg));
}
}
/**
* Represents a function that accepts three arguments to produce a {@code CommandResponse}. The arguments were
* extracted from a given JSON beforehand.
*
* @param <T> the type of the result of the function.
*/
@FunctionalInterface
public interface FactoryMethodFunction<T extends CommandResponse> {
/**
* Creates a {@code CommandResponse} with the help of the given arguments.
*
* @param statusCode the status of the response.
* @return the command response.
*/
T create(HttpStatusCode statusCode);
}
}