-
Notifications
You must be signed in to change notification settings - Fork 3
feat(additional-properties): add typed additional properties support for models #106
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
15 commits
Select commit
Hold shift + click to select a range
d0e989b
feat(additional-properties): add typed additional properties support …
sufyankhanrao e341903
updates README and fixes the Java 8 issue
sufyankhanrao 9afbfe2
fixes the java 8 version support
sufyankhanrao c388466
fixes the Map.Of issue that is supported since Java 11
sufyankhanrao d02220c
fixed some of the linting issues and adds utility for safe serializat…
sufyankhanrao 98e6d73
fixed linting issues
sufyankhanrao 5935ff8
refactors code for linting issues
sufyankhanrao 6141f33
fixed name of constants
sufyankhanrao e9ce9df
fixes the toBuilder method
sufyankhanrao 10e5b51
fixed linting issues
sufyankhanrao 4b82803
fixes liniting issue
sufyankhanrao e8c49b1
refactor: added suggestion from comments
haseeb-mhr a1e0fc9
refactor: added suggestion from comments
haseeb-mhr a1e4816
Merge branch '105-add-typed-additional-propery-support' of https://gi…
haseeb-mhr a4f996d
add AdditionalProperties class in README.md
hamzamahmood File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
113 changes: 113 additions & 0 deletions
113
src/main/java/io/apimatic/core/types/AdditionalProperties.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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
213
src/main/java/io/apimatic/core/utilities/ConversionHelper.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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; | ||
| } | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.