package com.sebastian_daschner.jaxrs_analyzer.backend; import com.sebastian_daschner.jaxrs_analyzer.model.rest.TypeIdentifier; import com.sebastian_daschner.jaxrs_analyzer.model.rest.TypeRepresentation; import com.sebastian_daschner.jaxrs_analyzer.model.rest.TypeRepresentationVisitor; import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; import static com.sebastian_daschner.jaxrs_analyzer.backend.ComparatorUtils.mapKeyComparator; import static com.sebastian_daschner.jaxrs_analyzer.model.Types.*; /** * Adds the JSON representation of type identifiers to String builders. * * @author Sebastian Daschner */ class JsonRepresentationAppender implements TypeRepresentationVisitor { private final StringBuilder builder; private final Map<TypeIdentifier, TypeRepresentation> representations; private int collectionDepth = 0; private Set<TypeIdentifier> visitedTypes = new HashSet<>(); JsonRepresentationAppender(final StringBuilder builder, final Map<TypeIdentifier, TypeRepresentation> representations) { this.builder = builder; this.representations = representations; } @Override public void visit(TypeRepresentation.ConcreteTypeRepresentation representation) { if (representation.getProperties().isEmpty()) builder.append(toPrimitiveType(representation.getIdentifier())); else { builder.append('{'); visitedTypes.add(representation.getIdentifier()); representation.getProperties().entrySet().stream().sorted(mapKeyComparator()).forEach(e -> { builder.append('"').append(e.getKey()).append("\":"); final TypeRepresentation nestedRepresentation = representations.get(e.getValue()); if (nestedRepresentation == null) builder.append(toPrimitiveType(e.getValue())); else if (visitedTypes.contains(e.getValue())) // prevent infinite loop from recursively nested types builder.append("{}"); else nestedRepresentation.accept(this); builder.append(','); }); visitedTypes.remove(representation.getIdentifier()); builder.deleteCharAt(builder.length() - 1).append('}'); } if (collectionDepth > 0) { builder.append(new String(new char[collectionDepth]).replace('\0', ']')); collectionDepth = 0; } } @Override public void visit(TypeRepresentation.CollectionTypeRepresentation representation) { builder.append('['); collectionDepth++; } @Override public void visit(final TypeRepresentation.EnumTypeRepresentation representation) { final String values = representation.getEnumValues().stream().sorted() .map(s -> '"' + s + '"') .collect(Collectors.joining("|")); builder.append(values.isEmpty() ? "\"string\"" : values); } private static String toPrimitiveType(final TypeIdentifier value) { final String type = value.getType(); if (STRING.equals(type)) return "\"string\""; if (BOOLEAN.equals(type) || PRIMITIVE_BOOLEAN.equals(type)) return "false"; if (INTEGER_TYPES.contains(type)) return "0"; if (DOUBLE_TYPES.contains(type)) return "0.0"; return "{}"; } }