de.gold.scim.common.utils.JsonHelper Maven / Gradle / Ivy
The newest version!
package de.gold.scim.common.utils;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import org.apache.commons.lang3.StringUtils;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.node.TextNode;
import de.gold.scim.common.constants.ScimType;
import de.gold.scim.common.exceptions.IncompatibleAttributeException;
import de.gold.scim.common.exceptions.InternalServerException;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
/**
* author Pascal Knueppel
* created at: 28.09.2019 - 00:05
*
*/
@Slf4j
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public final class JsonHelper
{
/**
* will read a json document from the classpath
*
* @param classPathLocation the location of the document
* @return the parsed json document
*/
public static JsonNode loadJsonDocument(String classPathLocation)
{
log.trace("trying to read classpath resource from: {}", classPathLocation);
try (InputStream inputStream = JsonHelper.class.getResourceAsStream(classPathLocation))
{
return new ObjectMapper().readTree(inputStream);
}
catch (IOException e)
{
throw de.gold.scim.common.exceptions.IOException.builder().message(e.getMessage()).cause(e).build();
}
}
/**
* will read a json document from the classpath
*
* @param classPathLocation the location of the document
* @return the parsed json document
*/
public static T loadJsonDocument(String classPathLocation, Class type)
{
log.trace("trying to read classpath resource from: {}", classPathLocation);
try (InputStream inputStream = JsonHelper.class.getResourceAsStream(classPathLocation))
{
JsonNode jsonNode = new ObjectMapper().readTree(inputStream);
return copyResourceToObject(jsonNode, type);
}
catch (IOException e)
{
throw de.gold.scim.common.exceptions.IOException.builder().message(e.getMessage()).cause(e).build();
}
}
/**
* will read a json document from a file
*
* @param file the location of the document
* @return the parsed json document
*/
public static T loadJsonDocument(File file, Class type)
{
log.trace("trying to read classpath resource from: {}", file.getAbsolutePath());
try (InputStream inputStream = new FileInputStream(file))
{
JsonNode jsonNode = new ObjectMapper().readTree(inputStream);
return copyResourceToObject(jsonNode, type);
}
catch (IOException e)
{
throw de.gold.scim.common.exceptions.IOException.builder().message(e.getMessage()).cause(e).build();
}
}
/**
* will read a json document from a file
*
* @param file the location of the document
* @return the parsed json document
*/
public static JsonNode loadJsonDocument(File file)
{
log.trace("trying to read classpath resource from: {}", file.getAbsolutePath());
try (InputStream inputStream = new FileInputStream(file))
{
return new ObjectMapper().readTree(inputStream);
}
catch (IOException e)
{
throw de.gold.scim.common.exceptions.IOException.builder().message(e.getMessage()).cause(e).build();
}
}
/**
* will read a json document from the given string
*
* @param jsonDocument the direct json representation
* @return the parsed json document
*/
public static JsonNode readJsonDocument(String jsonDocument)
{
if (StringUtils.isBlank(jsonDocument))
{
return null;
}
log.trace("trying to read json document: {}", jsonDocument);
try (Reader reader = new StringReader(jsonDocument))
{
return new ObjectMapper().readTree(reader);
}
catch (IOException e)
{
throw de.gold.scim.common.exceptions.IOException.builder()
.message("Invalid content, the document could not be parsed")
.cause(e)
.build();
}
}
/**
* will read a json document from the given string
*
* @param jsonDocument the direct json representation
* @return the parsed json document
*/
public static T readJsonDocument(String jsonDocument, Class type)
{
log.trace("trying to read json document: {}", jsonDocument);
try (Reader reader = new StringReader(jsonDocument))
{
JsonNode jsonNode = new ObjectMapper().readTree(reader);
return copyResourceToObject(jsonNode, type);
}
catch (IOException e)
{
throw de.gold.scim.common.exceptions.IOException.builder()
.message("Invalid content, the document could not be parsed")
.cause(e)
.build();
}
}
/**
* tries to get an array from the given json node
*
* @param jsonNode the json node from which the array should be extracted
* @param name the name of the json array attribute
* @return the json array attribute or an empty if the attribute is not present
*/
public static Optional getArrayAttribute(JsonNode jsonNode, String name)
{
JsonNode attribute = Objects.requireNonNull(jsonNode, "jsonNode must not be null").get(name);
if (attribute == null)
{
return Optional.empty();
}
if (attribute.isArray())
{
return Optional.of((ArrayNode)attribute);
}
throw IncompatibleAttributeException.builder()
.message("attribute with name '" + name + "' is not of type array")
.build();
}
/**
* tries to get an json object from the given json node
*
* @param jsonNode the json node from which the json object should be extracted
* @param name the name of the json object attribute
* @return the json object attribute or an empty if the attribute is not present
*/
public static Optional getObjectAttribute(JsonNode jsonNode, String name)
{
JsonNode attribute = Objects.requireNonNull(jsonNode, "jsonNode must not be null").get(name);
if (attribute == null)
{
return Optional.empty();
}
if (attribute.isObject())
{
return Optional.of((ObjectNode)attribute);
}
throw IncompatibleAttributeException.builder()
.message("attribute with name '" + name + "' is not of type object")
.build();
}
/**
* extracts a list of simple attributes from the given json node
*
* @param jsonNode the json document containing an array with simple attributes
* @param attributeName the name of the attribute that is an array with simple attributes
* @return a list of attributes or an empty
*/
public static Optional> getSimpleAttributeArray(JsonNode jsonNode, String attributeName)
{
return getSimpleAttributeArray(jsonNode, attributeName, String.class);
}
/**
* extracts a list of simple attributes from the given json node
*
* @param jsonNode the json document containing an array with simple attributes
* @param attributeName the name of the attribute that is an array with simple attributes
* @param type the type of the values within the array
* @return a list of attributes or an empty
*/
public static Optional> getSimpleAttributeArray(JsonNode jsonNode, String attributeName, Class type)
{
Optional simpleArrayOptional = getArrayAttribute(jsonNode, attributeName);
if (!simpleArrayOptional.isPresent())
{
return Optional.empty();
}
JsonNode simpleArray = simpleArrayOptional.get();
if (simpleArray.isObject())
{
final String errorMessage = "attribute '" + attributeName + "' is not a simple array attribute";
throw IncompatibleAttributeException.builder().message(errorMessage).build();
}
List arrayResult = new ArrayList<>();
for ( JsonNode node : simpleArray )
{
getAsAttribute(node, type).ifPresent(arrayResult::add);
}
return Optional.of(arrayResult);
}
/**
* will get a string attribute with the given name from the given json node
*
* @param jsonNode the json node to get the attribute from
* @param name the name of the attribute
* @return the value as string or an empty
*/
public static Optional getSimpleAttribute(JsonNode jsonNode, String name)
{
return getSimpleAttribute(jsonNode, name, String.class);
}
/**
* will get a string attribute with the given name from the given json node
*
* @param jsonNode the json node to get the attribute from
* @param name the name of the attribute
* @param type the type of the attribute to return
* @return the value of the given type or an empty
*/
public static Optional getSimpleAttribute(JsonNode jsonNode, String name, Class type)
{
JsonNode attribute = Objects.requireNonNull(jsonNode, "jsonNode must not be null").get(name);
if (attribute == null)
{
return Optional.empty();
}
if (attribute.isNull())
{
return Optional.empty();
}
if (attribute.isArray())
{
throw IncompatibleAttributeException.builder()
.message("attribute '" + name + "' is not of type " + type.getSimpleName())
.build();
}
return getAsAttribute(attribute, type);
}
/**
* will remove an attribute from the given jsonNode
*
* @param jsonNode the json node from which the attribute should be removed
* @param attributeName the name of the attribute to remove
*/
public static JsonNode removeAttribute(JsonNode jsonNode, String attributeName)
{
return ((ObjectNode)jsonNode).remove(attributeName);
}
/**
* will remove a simple value from a simple array node in the given json document
*
* @param jsonNode the array from which the value should be removed
* @param value the value that should be removed from the document
*/
public static JsonNode removeSimpleAttributeFromArray(JsonNode jsonNode, String value)
{
if (jsonNode == null)
{
return null;
}
if (!jsonNode.isArray())
{
log.error("cannot remove value '{}' from a json node that is not a simple array", value);
return jsonNode;
}
int index = -1;
for ( int i = 0 ; i < jsonNode.size() ; i++ )
{
JsonNode simpleNode = jsonNode.get(i);
if (simpleNode.isObject() || simpleNode.isArray())
{
break;
}
if (simpleNode.textValue().equals(value))
{
index = i;
break;
}
}
if (index > -1)
{
((ArrayNode)jsonNode).remove(index);
}
else
{
log.error("could not remove value '{}' from json array because its sub-elements are not primitive types", value);
}
return jsonNode;
}
/**
* will remove an attribute from the given jsonNode
*
* @param jsonNode the json node from which the attribute should be removed
* @param attributeName the name of the attribute to remove
* @param newAttriute the new attribute that should be added
*/
public static JsonNode addAttribute(JsonNode jsonNode, String attributeName, JsonNode newAttriute)
{
return ((ObjectNode)jsonNode).set(attributeName, newAttriute);
}
/**
* will remove an attribute from the given jsonNode
*
* @param jsonArray the json node from which the attribute should be removed
* @param newAttriute the new attribute that should be added
*/
public static JsonNode addAttributeToArray(JsonNode jsonArray, JsonNode newAttriute)
{
return ((ArrayNode)jsonArray).add(newAttriute);
}
/**
* will remove an attribute from the given jsonNode
*
* @param jsonNode the json node from which the attribute should be removed
* @param attributeName the name of the attribute to remove
* @param value the value of the new replaced node
*/
public static JsonNode writeValue(JsonNode jsonNode, String attributeName, T value)
{
JsonNode valueNode = new TextNode(String.valueOf(value));
return ((ObjectNode)jsonNode).replace(attributeName, valueNode);
}
/**
* will remove an attribute from the given jsonNode
*
* @param jsonNode the json node from which the attribute should be removed
* @param attributeName the name of the attribute to remove
* @param replaceNode the new node that should be used as replacement
*/
public static JsonNode replaceNode(JsonNode jsonNode, String attributeName, JsonNode replaceNode)
{
return ((ObjectNode)jsonNode).replace(attributeName, replaceNode);
}
/**
* gets the simple attribute of the given json node
*
* @param attribute the json node that should be a simple attribute
* @param type the type to extract
* @return the extracted attribute or an empty
*/
private static Optional getAsAttribute(JsonNode attribute, Class type)
{
if (String.class.equals(type))
{
return Optional.of((T)attribute.asText());
}
if (Boolean.class.equals(type))
{
return Optional.of((T)Boolean.valueOf(attribute.asBoolean()));
}
if (Integer.class.equals(type))
{
return Optional.of((T)Integer.valueOf(attribute.asInt()));
}
if (Long.class.equals(type))
{
return Optional.of((T)Long.valueOf(attribute.asLong()));
}
if (Float.class.equals(type))
{
return Optional.of((T)Float.valueOf((float)attribute.asDouble()));
}
if (Double.class.equals(type))
{
return Optional.of((T)Double.valueOf(attribute.asDouble()));
}
if (Long.class.equals(type))
{
return Optional.of((T)Long.valueOf(attribute.asLong()));
}
throw IncompatibleAttributeException.builder()
.message("attribute '" + attribute + "' is not of type" + type.getSimpleName())
.build();
}
/**
* creates a new instance of the given type and moves the content from the resource into the new node
*
* @param resource the resource that holds the content that must be moved to the new object
* @param type the type from which an instance will be created with a noArgs constructor
* @return a newly created instance with the content of the {@code resource}-node
*/
public static T copyResourceToObject(JsonNode resource, Class type)
{
if (resource == null)
{
return null;
}
if (resource.isArray())
{
throw new IncompatibleAttributeException("operation not possible for array", null, null,
ScimType.Custom.INVALID_PARAMETERS);
}
if (type.isAssignableFrom(resource.getClass()))
{
return (T)resource;
}
T newInstance = getNewInstance(type);
resource.fields().forEachRemaining(stringJsonNodeEntry -> {
JsonHelper.addAttribute(newInstance, stringJsonNodeEntry.getKey(), stringJsonNodeEntry.getValue());
});
return newInstance;
}
/**
* creates a new instance of the given type
*
* @param type the type from which a new instance will be created
* @param the type must define a noArgs constructor
* @return the newly created instance
*/
private static T getNewInstance(Class type)
{
try
{
return type.newInstance();
}
catch (InstantiationException | IllegalAccessException e)
{
throw new InternalServerException("could not create instance of type '" + type + "': " + e.getMessage(), e, null);
}
}
/**
* will extract a scim attribute by its scim-name.
*
* @param attributeName the scim name of the attribute e.g. "userName" of "name.givenName"
* @return the json node or an empty
*/
public static Optional getSimpleAttributeByName(JsonNode jsonNode, String attributeName)
{
String[] nameParts = attributeName.split("\\.");
JsonNode subNode = jsonNode.get(nameParts[0]);
if (nameParts.length == 1)
{
return Optional.ofNullable(subNode);
}
return Optional.ofNullable(subNode.get(nameParts[1]));
}
/**
* validates if the given string structure is valid json or not
*
* @param json the string to validate
* @return true if the given string is a valid json structure, false else
*/
public static boolean isValidJson(final String json)
{
try
{
final JsonParser parser = new ObjectMapper().getFactory().createParser(json);
while (parser.nextToken() != null)
{}
return true;
}
catch (IOException ex)
{
log.trace(ex.getMessage());
return false;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy