Skip to content

Commit

Permalink
first attempt at generics
Browse files Browse the repository at this point in the history
  • Loading branch information
euberseder-hubspot committed Dec 22, 2023
1 parent 9c6257c commit bbc0b7f
Showing 1 changed file with 60 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ public boolean isPreserveUnknownFields() {
*/
protected T internalFrom(TypeDef definition, String... ignore) {
List<InternalSchemaSwap> schemaSwaps = new ArrayList<>();
T ret = internalFromImpl(definition, new HashSet<>(), schemaSwaps, ignore);
T ret = internalFromImpl(definition, new HashSet<>(), schemaSwaps, new ParameterMap(new HashMap<>()), ignore);
validateRemainingSchemaSwaps("unmatched class", schemaSwaps);
return ret;
}
Expand Down Expand Up @@ -277,7 +277,7 @@ private void validateRemainingSchemaSwaps(String error, List<InternalSchemaSwap>
}
}

private T internalFromImpl(TypeDef definition, Set<String> visited, List<InternalSchemaSwap> schemaSwaps, String... ignore) {
private T internalFromImpl(TypeDef definition, Set<String> visited, List<InternalSchemaSwap> schemaSwaps, ParameterMap parameterMap, String... ignore) {
final B builder = newBuilder();
Set<String> ignores =
ignore.length > 0 ? new LinkedHashSet<>(Arrays.asList(ignore)) : Collections
Expand Down Expand Up @@ -312,7 +312,7 @@ private T internalFromImpl(TypeDef definition, Set<String> visited, List<Interna
continue;
}

final PropertyFacade facade = new PropertyFacade(property, accessors, currentSchemaSwaps);
final PropertyFacade facade = new PropertyFacade(property, accessors, currentSchemaSwaps, parameterMap);
final Property possiblyRenamedProperty = facade.process();
final Set<InternalSchemaSwap> matchedSchemaSwaps = facade.getMatchedSchemaSwaps();
currentSchemaSwaps.removeAll(matchedSchemaSwaps);
Expand All @@ -324,7 +324,7 @@ private T internalFromImpl(TypeDef definition, Set<String> visited, List<Interna
} else if (facade.ignored) {
continue;
}
final T schema = internalFromImpl(name, possiblyRenamedProperty.getTypeRef(), visited, schemaSwaps);
final T schema = internalFromImpl(name, possiblyRenamedProperty.getTypeRef(), visited, schemaSwaps, parameterMap);
if (facade.preserveUnknownFields) {
preserveUnknownFields = true;
}
Expand Down Expand Up @@ -363,6 +363,47 @@ private Map<String, Method> indexPotentialAccessors(TypeDef definition) {
return accessors;
}

private static class ParameterMap {
final Map<String, TypeRef> mappings;

ParameterMap(Map<String, TypeRef> mappings) {
this.mappings = mappings;
}

TypeRef exchange(TypeRef original){
return exchange(original, true);
}

TypeRef exchange(TypeRef original, boolean throwOnFailedLookup){
if (original instanceof TypeParamRef) {
String name = ((TypeParamRef) original).getName();
TypeRef ref = mappings.get(name);
if(ref != null) {
return ref;
}
if(throwOnFailedLookup) {
throw new RuntimeException(String.format("Could not find type mapping for parametrized type %s", name));
}
}
return original;
}

static ParameterMap from(ClassRef classRef, ParameterMap parentMappings) {
TypeDef def = Types.typeDefFrom(classRef);

Map<String, TypeRef> mappings = new HashMap<>();
if(!def.getParameters().isEmpty()) {
for(int i=0; i<def.getParameters().size(); i++) {
mappings.put(
def.getParameters().get(i).getName(),
parentMappings.exchange(classRef.getArguments().get(i))
);
}
}

return new ParameterMap(mappings);
}
}

private static class PropertyOrAccessor {
private final Collection<AnnotationRef> annotations;
Expand Down Expand Up @@ -515,6 +556,7 @@ private static class PropertyFacade {
private final List<PropertyOrAccessor> propertyOrAccessors = new ArrayList<>(4);
private final Set<InternalSchemaSwap> schemaSwaps;
private final Set<InternalSchemaSwap> matchedSchemaSwaps;
private final ParameterMap parameterMap;
private String renamedTo;
private String description;
private String defaultValue;
Expand All @@ -530,9 +572,10 @@ private static class PropertyFacade {
private String descriptionContributedBy;
private TypeRef schemaFrom;

public PropertyFacade(Property property, Map<String, Method> potentialAccessors, Set<InternalSchemaSwap> schemaSwaps) {
public PropertyFacade(Property property, Map<String, Method> potentialAccessors, Set<InternalSchemaSwap> schemaSwaps, ParameterMap parameterMap) {
original = property;
this.schemaSwaps = schemaSwaps;
this.parameterMap = parameterMap;
this.matchedSchemaSwaps = new HashSet<>();
final String capitalized = property.getNameCapitalized();
final String name = property.getName();
Expand Down Expand Up @@ -610,7 +653,7 @@ public Property process() {
}
});

TypeRef typeRef = schemaFrom != null ? schemaFrom : original.getTypeRef();
TypeRef typeRef = schemaFrom != null ? schemaFrom : parameterMap.exchange(original.getTypeRef());
String finalName = renamedTo != null ? renamedTo : original.getName();

return new Property(original.getAnnotations(), typeRef, finalName,
Expand Down Expand Up @@ -685,16 +728,16 @@ private String extractUpdatedNameFromJacksonPropertyIfPresent(Property property)
* @return the structural schema associated with the specified property
*/
public T internalFrom(String name, TypeRef typeRef) {
return internalFromImpl(name, typeRef, new HashSet<>(), new ArrayList<>());
return internalFromImpl(name, typeRef, new HashSet<>(), new ArrayList<>(), new ParameterMap(new HashMap<>()));
}

private T internalFromImpl(String name, TypeRef typeRef, Set<String> visited, List<InternalSchemaSwap> schemaSwaps) {
private T internalFromImpl(String name, TypeRef typeRef, Set<String> visited, List<InternalSchemaSwap> schemaSwaps, ParameterMap parameterMap) {
// Note that ordering of the checks here is meaningful: we need to check for complex types last
// in case some "complex" types are handled specifically
if (typeRef.getDimensions() > 0 || io.sundr.model.utils.Collections.isCollection(typeRef)) { // Handle Collections & Arrays
final TypeRef collectionType = TypeAs.combine(TypeAs.UNWRAP_ARRAY_OF, TypeAs.UNWRAP_COLLECTION_OF)
.apply(typeRef);
final T schema = internalFromImpl(name, collectionType, visited, schemaSwaps);
final T schema = internalFromImpl(name, parameterMap.exchange(collectionType), visited, schemaSwaps, parameterMap);
return arrayLikeProperty(schema);
} else if (io.sundr.model.utils.Collections.IS_MAP.apply(typeRef)) { // Handle Maps
final TypeRef keyType = TypeAs.UNWRAP_MAP_KEY_OF.apply(typeRef);
Expand All @@ -704,15 +747,15 @@ private T internalFromImpl(String name, TypeRef typeRef, Set<String> visited, Li
}

final TypeRef valueType = TypeAs.UNWRAP_MAP_VALUE_OF.apply(typeRef);
T schema = internalFromImpl(name, valueType, visited, schemaSwaps);
T schema = internalFromImpl(name, parameterMap.exchange(valueType, false), visited, schemaSwaps, parameterMap);
if (schema == null) {
LOGGER.warn("Property '{}' with '{}' value type is mapped to 'object' because its CRD representation cannot be extracted.", name, typeRef);
schema = internalFromImpl(name, OBJECT_REF, visited, schemaSwaps);
schema = internalFromImpl(name, OBJECT_REF, visited, schemaSwaps, parameterMap);
}

return mapLikeProperty(schema);
} else if (io.sundr.model.utils.Optionals.isOptional(typeRef)) { // Handle Optionals
return internalFromImpl(name, TypeAs.UNWRAP_OPTIONAL_OF.apply(typeRef), visited, schemaSwaps);
return internalFromImpl(name, parameterMap.exchange(TypeAs.UNWRAP_OPTIONAL_OF.apply(typeRef)), visited, schemaSwaps, parameterMap);
} else {
final String typeName = COMMON_MAPPINGS.get(typeRef);
if (typeName != null) { // we have a type that we handle specifically
Expand All @@ -724,9 +767,9 @@ private T internalFromImpl(String name, TypeRef typeRef, Set<String> visited, Li
} else {
if (typeRef instanceof ClassRef) { // Handle complex types
ClassRef classRef = (ClassRef) typeRef;
TypeDef def = Types.typeDefFrom(classRef);

// check if we're dealing with an enum
TypeDef def = Types.typeDefFrom(classRef);
if (def.isEnum()) {
final JsonNode[] enumValues = def.getProperties().stream()
.map(this::extractUpdatedNameFromJacksonPropertyIfPresent)
Expand All @@ -735,7 +778,7 @@ private T internalFromImpl(String name, TypeRef typeRef, Set<String> visited, Li
.toArray(JsonNode[]::new);
return enumProperty(enumValues);
} else {
return resolveNestedClass(name, def, visited, schemaSwaps);
return resolveNestedClass(name, classRef, visited, schemaSwaps, parameterMap);
}

}
Expand All @@ -747,7 +790,8 @@ private T internalFromImpl(String name, TypeRef typeRef, Set<String> visited, Li
// Flag to detect cycles
private boolean resolving = false;

private T resolveNestedClass(String name, TypeDef def, Set<String> visited, List<InternalSchemaSwap> schemaSwaps) {
private T resolveNestedClass(String name, ClassRef classRef, Set<String> visited, List<InternalSchemaSwap> schemaSwaps, ParameterMap parameterMap) {
TypeDef def = Types.typeDefFrom(classRef);
if (!resolving) {
visited.clear();
resolving = true;
Expand All @@ -759,7 +803,7 @@ private T resolveNestedClass(String name, TypeDef def, Set<String> visited, List
visited.add(visitedName);
}

T res = internalFromImpl(def, visited, schemaSwaps);
T res = internalFromImpl(def, visited, schemaSwaps, ParameterMap.from(classRef, parameterMap));
resolving = false;
return res;
}
Expand Down

0 comments on commit bbc0b7f

Please sign in to comment.