/** * Inlines outer-level aliases and references, but not within objects or container types. * <p> * For example, a reference to an alias A which wraps another alias B which wraps a {@code list<integer>}, we'll * return {@code list<integer>}. Note that these are outer-level references being resolved. * However, if the aforementioned list's inner type was also a reference e.g. {@code list<C>}, we * wouldn't unwrap that, so we'd just return the same {@code list<C>}. */ public Either<TypeDefinition, Type> dealias(Type type) { return type.accept(this); }
/** * Inlines outer-level aliases and references, but not within objects or container types. * <p> * For example, a reference to an alias A which wraps another alias B which wraps a {@code list<integer>}, we'll * return {@code list<integer>}. Note that these are outer-level references being resolved. * However, if the aforementioned list's inner type was also a reference e.g. {@code list<C>}, we * wouldn't unwrap that, so we'd just return the same {@code list<C>}. */ public Either<TypeDefinition, Type> dealias(Type type) { return type.accept(this); }
private static Optional<TypeName> resolveReferenceType(Type type) { if (type.accept(TypeVisitor.IS_REFERENCE)) { return Optional.of(type.accept(TypeVisitor.REFERENCE)); } else if (type.accept(TypeVisitor.IS_PRIMITIVE)) { return Optional.of( TypeName.of(type.accept(TypeVisitor.PRIMITIVE).get().name(), "")); } return Optional.empty(); }
private static void checkForComplexType(FieldDefinition typeDef) { if (typeDef.getType().accept(TypeVisitor.IS_MAP)) { MapType mapType = typeDef.getType().accept(TypeVisitor.MAP); if (!mapType.getKeyType().accept(TypeVisitor.IS_PRIMITIVE_OR_REFERENCE)) { throw new IllegalStateException( String.format("Complex type '%s' not allowed in map key: %s.", mapType.getKeyType(), typeDef)); } } } }
private static Boolean recursivelyValidate(Type type, DealiasingTypeVisitor visitor) { return visitor.dealias(type).fold( typeDefinition -> typeDefinition.accept(TypeDefinitionVisitor.IS_ENUM), subType -> { boolean definedPrimitive = subType.accept(TypeVisitor.IS_PRIMITIVE); boolean optionalPrimitive = subType.accept(TypeVisitor.IS_OPTIONAL) && recursivelyValidate(subType.accept(TypeVisitor.OPTIONAL).getItemType(), visitor); return definedPrimitive || optionalPrimitive; }); } }
private static boolean recursivelyFindNestedOptionals( Type type, Map<TypeName, TypeDefinition> definitionMap, boolean isOptionalSeen) { if (type.accept(TypeVisitor.IS_REFERENCE)) { TypeDefinition referenceDefinition = definitionMap.get(type.accept(TypeVisitor.REFERENCE)); // we only care about reference of alias type if (referenceDefinition != null && referenceDefinition.accept(TypeDefinitionVisitor.IS_ALIAS)) { AliasDefinition aliasDef = referenceDefinition.accept(TypeDefinitionVisitor.ALIAS); return recursivelyFindNestedOptionals(aliasDef.getAlias(), definitionMap, isOptionalSeen); } } else if (type.accept(TypeVisitor.IS_OPTIONAL)) { if (isOptionalSeen) { return true; } return recursivelyFindNestedOptionals(type.accept(TypeVisitor.OPTIONAL).getItemType(), definitionMap, true); } return false; } }
@Override public void validate(EndpointDefinition definition, DealiasingTypeVisitor dealiasingTypeVisitor) { definition.getArgs() .stream() .filter(arg -> !arg.getParamType().accept(ParameterTypeVisitor.IS_BODY)) .forEach(arg -> { boolean isValid = dealiasingTypeVisitor.dealias(arg.getType()) .fold( typeDefinition -> true, type -> !type.accept(TypeVisitor.IS_BINARY) && !type.accept(TypeVisitor.IS_ANY) ); Preconditions.checkArgument( isValid, "Non body parameters cannot be of the 'binary' type: '%s' is not allowed", arg.getArgName()); }); } }
@Override public void validate(EndpointDefinition definition, DealiasingTypeVisitor dealiasingTypeVisitor) { definition.getArgs().stream() .filter(entry -> entry.getParamType().accept(ParameterTypeVisitor.IS_PATH)) .forEach(entry -> { Either<TypeDefinition, Type> resolvedType = dealiasingTypeVisitor.dealias(entry.getType()); Boolean isValid = resolvedType.fold( typeDefinition -> typeDefinition.accept(TypeDefinitionVisitor.IS_ENUM), type -> type.accept(TypeVisitor.IS_PRIMITIVE)); Preconditions.checkState(isValid, "Path parameters must be primitives or aliases: \"%s\" is not allowed", entry.getArgName()); }); } }
@Override public void validate(EndpointDefinition definition, DealiasingTypeVisitor dealiasingTypeVisitor) { definition.getArgs().stream() .filter(entry -> entry.getParamType().accept(ParameterTypeVisitor.IS_PATH) || entry.getParamType().accept(ParameterTypeVisitor.IS_QUERY)) .forEach(entry -> { Either<TypeDefinition, Type> conjureType = dealiasingTypeVisitor.dealias(entry.getType()); boolean isValid = conjureType.fold( typeDefinition -> true, type -> !type.accept(TypeVisitor.IS_PRIMITIVE) || type.accept(TypeVisitor.PRIMITIVE).get() != PrimitiveType.Value.BEARERTOKEN ); Preconditions.checkState(isValid, "Path or query parameters of type 'bearertoken' are not allowed as this " + "would introduce a security vulnerability: \"%s\"", entry.getArgName()); }); } }
private static Boolean recursivelyValidate(Type type, DealiasingTypeVisitor visitor) { return visitor.dealias(type).fold( typeDefinition -> typeDefinition.accept(TypeDefinitionVisitor.IS_ENUM), subType -> subType.accept(new Type.Visitor<Boolean>() { @Override public Boolean visitPrimitive(PrimitiveType value) {