Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ Core lib's Maven group ID is `io.apimatic`, and its artifact ID is `core`.
| [`CoreJsonObject`](./src/main/java/io/apimatic/core/utilities/CoreJsonObject.java) | Wrapper class for JSON object |
| [`CoreJsonValue`](./src/main/java/io/apimatic/core/utilities/CoreJsonValue.java) | Wrapper class for JSON value |
| [`TestHelper`](./src/main/java/io/apimatic/core/utilities/TestHelper.java) | Contains utility methods for comparing objects, arrays and files |
| [`AdditionalProperties`](./src/main/java/io/apimatic/core/types/AdditionalProperties.java) | A generic class for managing additional properties in a model. |
| [`ConversionHelper`](./src/main/java/io/apimatic/core/utilities/ConversionHelper.java) | A Helper class for the coversion of type (provided as function) for all structures (array, map, array of map, n-dimensional arrays etc) supported in the SDK. |

## Interfaces

Expand Down
113 changes: 113 additions & 0 deletions src/main/java/io/apimatic/core/types/AdditionalProperties.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
package io.apimatic.core.types;

import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import com.fasterxml.jackson.annotation.JsonGetter;

/**
* A generic class for managing additional properties in a model.
*
* @param <T> the type of the additional properties.
*/
public class AdditionalProperties<T> {

/**
* Map to store additional properties.
*/
private final Map<String, T> properties = new LinkedHashMap<>();

/**
* Set to store model properties.
*/
private final Set<String> modelProperties = new HashSet<>();

/**
* Default constructor.
*/
public AdditionalProperties() {
// Default constructor
}

/**
* Parameterized constructor.
* @param classInstance The instance of the class with additional properties.
*/
public AdditionalProperties(final Class<?> classInstance) {
Method[] methods = classInstance.getMethods();
for (Method method : methods) {
JsonGetter jsonGetter = method.getAnnotation(JsonGetter.class);
if (jsonGetter != null) {
modelProperties.add(jsonGetter.value());
}
}
}

/**
* Gets the additional properties.
* @return the map of additional properties.
*/
public Map<String, T> getAdditionalProperties() {
return properties;
}

/**
* Sets an additional property.
* @param key The key for the additional property.
* @param value The value of the additional property.
* @throws IllegalArgumentException if there is a conflict between the key and
* any model property.
*/
public void setAdditionalProperty(String key, T value) {
if (key == null || key.trim().isEmpty()) {
throw new IllegalArgumentException("Key cannot be null or empty.");
}

if (modelProperties.contains(key)) {
throw new IllegalArgumentException(
"Key '" + key + "' conflicts with a model property.");
}

properties.put(key, value);
}

/**
* Sets an additional property with an option to skip null values.
* @param key The key for the additional property.
* @param value The value of the additional property.
* @param skipNullValue If true, null values will be skipped.
* @throws IllegalArgumentException if there is a conflict between the key and
* any model property.
*/
public void setAdditionalProperty(String key, T value, boolean skipNullValue) {
if (skipNullValue && value == null) {
return;
}

setAdditionalProperty(key, value);
}

@Override
public String toString() {
if (properties.isEmpty()) {
return "";
}

return properties.entrySet().stream().map(entry -> entry.getKey() + "=" + entry.getValue())
.collect(Collectors.joining(", ", ", ", ""));
}

/**
* Gets an additional property by key.
* @param key The key of the additional property to retrieve.
* @return the value of the additional property associated with the given key,
* or null if not found.
*/
public T getAdditionalProperty(String key) {
return properties.get(key);
}
}
213 changes: 213 additions & 0 deletions src/main/java/io/apimatic/core/utilities/ConversionHelper.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
package io.apimatic.core.utilities;

import java.util.AbstractMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
* A helper class for converting types of various structures supported in the
* SDK.
*/
public final class ConversionHelper {

/**
* Private constructor to prevent instantiation of this utility class.
*/
private ConversionHelper() {
// Prevent instantiation
}

/**
* Converts a single object to the specified type.
*
* @param <S> the type to convert to.
* @param value the object to convert.
* @param conversionFunction the function to apply for conversion.
* @return the converted object of type {@code S}, or null if conversion fails.
*/
public static <S> S convertToSimpleType(Object value, Function<Object, S> conversionFunction) {
try {
return conversionFunction.apply(value);
} catch (Exception e) {
return null;
}
}

/**
* Converts a map of objects to a map of the specified type.
*
* @param <S> the type of values in the resulting map.
* @param value the map of objects to convert.
* @param conversionFunction the function to apply for conversion of each value.
* @return a map with values converted to type {@code S}, or null if conversion
* fails.
*/
@SuppressWarnings("unchecked")
public static <S> Map<String, S> convertToMap(Object value,
Function<Object, S> conversionFunction) {
if (value == null) {
return null;
}

try {
Map<String, Object> valueMap = (Map<String, Object>) value;
return valueMap.entrySet().stream()
.map(entry -> new AbstractMap.SimpleEntry<>(entry.getKey(),
convertToSimpleType(entry.getValue(), conversionFunction)))
.filter(entry -> entry.getValue() != null)
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
} catch (Exception e) {
return null;
}
}

/**
* Converts a list of objects to a list of the specified type.
*
* @param <S> the type of elements in the resulting list.
* @param value the list of objects to convert.
* @param conversionFunction the function to apply for conversion of each item.
* @return a list with elements converted to type {@code S}, or null if
* conversion fails.
*/
@SuppressWarnings("unchecked")
public static <S> List<S> convertToArray(Object value,
Function<Object, S> conversionFunction) {
if (value == null) {
return null;
}

try {
List<Object> valueList = (List<Object>) value;
return valueList.stream().map(item -> convertToSimpleType(item, conversionFunction))
.filter(Objects::nonNull).collect(Collectors.toList());
} catch (Exception e) {
return null;
}
}

/**
* Converts a list of maps to a list of maps with values of the specified type.
*
* @param <S> the type of values in the maps of the resulting
* list.
* @param value the list of maps to convert.
* @param conversionFunction the function to apply for conversion of each map's
* values.
* @return a list of maps with converted values of type {@code S}, or null if
* conversion fails.
*/
@SuppressWarnings("unchecked")
public static <S> List<Map<String, S>> convertToArrayOfMap(Object value,
Function<Object, S> conversionFunction) {
if (value == null) {
return null;
}

try {
List<Object> valueList = (List<Object>) value;
return valueList.stream().map(item -> convertToMap(item, conversionFunction))
.filter(map -> map != null && !map.isEmpty()).collect(Collectors.toList());
} catch (Exception e) {
return null;
}
}

/**
* Converts a map of lists to a map with lists of the specified type.
*
* @param <S> the type of elements in the lists of the resulting
* map.
* @param value the map of lists to convert.
* @param conversionFunction the function to apply for conversion of each list's
* elements.
* @return a map with lists converted to type {@code S}, or null if conversion
* fails.
*/
@SuppressWarnings("unchecked")
public static <S> Map<String, List<S>> convertToMapOfArray(Object value,
Function<Object, S> conversionFunction) {
if (value == null) {
return null;
}

try {
Map<String, Object> valueMap = (Map<String, Object>) value;
return valueMap.entrySet().stream()
.map(entry -> new AbstractMap.SimpleEntry<>(entry.getKey(),
convertToArray(entry.getValue(), conversionFunction)))
.filter(entry -> entry.getValue() != null && !entry.getValue().isEmpty())
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
} catch (Exception e) {
return null;
}
}

/**
* Converts an n-dimensional array to a nested list with elements of the
* specified type.
*
* @param <T> the type of the nested structure.
* @param <S> the type of elements in the nested structure.
* @param value the n-dimensional array to convert.
* @param conversionFunction the function to apply for conversion of each
* element.
* @param dimensionCount the depth of the nested structure.
* @return a nested list with elements converted to type {@code S}, or null if
* conversion fails.
*/
@SuppressWarnings("unchecked")
public static <T, S> T convertToNDimensionalArray(Object value,
Function<Object, S> conversionFunction,
int dimensionCount) {
if (value == null) {
return null;
}

try {
return (T) convertToNDimensionalArrayInternal(value,
conversionFunction, dimensionCount);
} catch (Exception e) {
return null;
}
}

/**
* Applies the conversion function to the n-dimensional arrays recursively.
*
* @param <S> the type of elements in the nested structure.
* @param value the n-dimensional array to convert.
* @param conversionFunction the function to apply for conversion of each
* element.
* @param dimensionCount the depth of the nested structure.
* @return a nested list with elements converted to type {@code S}, or null if
* conversion fails.
*/
@SuppressWarnings("unchecked")
private static <S> List<?> convertToNDimensionalArrayInternal(Object value,
Function<Object, S> conversionFunction,
int dimensionCount) {
if (value == null) {
return null;
}

try {
if (dimensionCount == 1) {
return convertToArray(value, conversionFunction);
} else if (dimensionCount > 1) {
List<Object> valueList = (List<Object>) value;
return valueList.stream()
.map(item -> convertToNDimensionalArray(item,
conversionFunction, dimensionCount - 1))
.filter(item -> item != null && !((List<?>) item).isEmpty())
.collect(Collectors.toList());
}
} catch (Exception e) {
// Ignoring exception to handle silently.
}
return null;
}
}
Loading