Skip to content

Commit

Permalink
Fix sonar errors.
Browse files Browse the repository at this point in the history
Add more tests.
Move commons strings to constants
  • Loading branch information
altro3 committed Mar 24, 2024
1 parent 1a5df68 commit f80c0eb
Show file tree
Hide file tree
Showing 25 changed files with 1,004 additions and 867 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import io.swagger.v3.oas.annotations.Operation
import io.swagger.v3.oas.annotations.media.Content
import io.swagger.v3.oas.annotations.media.Schema
import io.swagger.v3.oas.annotations.responses.ApiResponse
import io.swagger.v3.oas.annotations.responses.ApiResponses
import io.swagger.v3.oas.annotations.tags.Tag

// end::imports[]
Expand All @@ -23,13 +22,9 @@ open class HelloController {
*/
@Get(uri = "/greetings/{name}", produces = [MediaType.TEXT_PLAIN])
@Operation(summary = "Greets a person", description = "A friendly greeting is returned")
// Please Note: Repeatable Annotations with non-SOURCE retentions are not yet supported with Kotlin, so we are using `@ApiResponses`
// instead of `@ApiResponse`, see https://youtrack.jetbrains.com/issue/KT-12794
@ApiResponses(
ApiResponse(content = [Content(mediaType = "text/plain", schema = Schema(type = "string"))]),
ApiResponse(responseCode = "400", description = "Invalid Name Supplied"),
ApiResponse(responseCode = "404", description = "Person not found")
)
@ApiResponse(content = [Content(mediaType = "text/plain", schema = Schema(type = "string"))])
@ApiResponse(responseCode = "400", description = "Invalid Name Supplied")
@ApiResponse(responseCode = "404", description = "Person not found")
@Tag(name = "greeting")
open fun greetings(name: String): Mono<String> {
return Mono.just("Hello $name, how are you doing?")
Expand Down
1 change: 1 addition & 0 deletions openapi/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ dependencies {
// this dependency needs to be updated manually. It's used by html2md
api(libs.managed.jsoup)

testImplementation(projects.micronautOpenapiAdoc)
testImplementation(mnSession.micronaut.session)
testImplementation(mn.micronaut.management)
testImplementation(mn.micronaut.inject.kotlin.test)
Expand Down

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,8 @@ public AnnProcessorEnvironment(ApplicationContextConfiguration configuration, Vi
if (isEnabled) {
Path projectPath = getProjectPath(context);
if (projectPath != null) {
projectDir = "file:" + projectPath.toString().replaceAll("\\\\", "/");
projectResourcesPath = projectDir + (projectDir.endsWith("/") ? StringUtils.EMPTY_STRING : "/") + "src/main/resources/";
projectDir = "file:" + projectPath.toString().replaceAll("\\\\", StringUtil.SLASH);
projectResourcesPath = projectDir + (projectDir.endsWith(StringUtil.SLASH) ? StringUtils.EMPTY_STRING : StringUtil.SLASH) + "src/main/resources/";
}

String configFileLocations = ContextUtils.getOptions(context).get(MICRONAUT_CONFIG_FILE_LOCATIONS);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,20 @@
import static io.micronaut.openapi.visitor.SchemaUtils.TYPE_STRING;
import static io.micronaut.openapi.visitor.SchemaUtils.processExtensions;
import static io.micronaut.openapi.visitor.Utils.resolveComponents;
import static io.micronaut.openapi.visitor.OpenApiModelProp.PROP_$REF;
import static io.micronaut.openapi.visitor.OpenApiModelProp.PROP_ALLOWABLE_VALUES;
import static io.micronaut.openapi.visitor.OpenApiModelProp.PROP_DEFAULT;
import static io.micronaut.openapi.visitor.OpenApiModelProp.PROP_DEFAULT_VALUE;
import static io.micronaut.openapi.visitor.OpenApiModelProp.PROP_DESCRIPTION;
import static io.micronaut.openapi.visitor.OpenApiModelProp.PROP_ENUM;
import static io.micronaut.openapi.visitor.OpenApiModelProp.PROP_EXAMPLES;
import static io.micronaut.openapi.visitor.OpenApiModelProp.PROP_EXTENSIONS;
import static io.micronaut.openapi.visitor.OpenApiModelProp.PROP_IN;
import static io.micronaut.openapi.visitor.OpenApiModelProp.PROP_NAME;
import static io.micronaut.openapi.visitor.OpenApiModelProp.PROP_ONE_FORMAT;
import static io.micronaut.openapi.visitor.OpenApiModelProp.PROP_REF;
import static io.micronaut.openapi.visitor.OpenApiModelProp.PROP_SCHEMA;
import static io.micronaut.openapi.visitor.OpenApiModelProp.PROP_TYPE;

/**
* Convert utilities methods.
Expand Down Expand Up @@ -180,7 +194,7 @@ public static Map<CharSequence, Object> toValueMap(Map<CharSequence, Object> val
for (Object o : a) {
processExtensions(extensions, (AnnotationValue<Extension>) o);
}
newValues.put("extensions", extensions);
newValues.put(PROP_EXTENSIONS, extensions);
} else if (Server.class.getName().equals(annotationName)) {
var servers = new ArrayList<Map<CharSequence, Object>>();
for (Object o : a) {
Expand All @@ -190,21 +204,21 @@ public static Map<CharSequence, Object> toValueMap(Map<CharSequence, Object> val
}
newValues.put(key, servers);
} else if (OAuthScope.class.getName().equals(annotationName)) {
Map<String, String> params = toTupleSubMap(a, "name", "description");
Map<String, String> params = toTupleSubMap(a, PROP_NAME, PROP_DESCRIPTION);
newValues.put(key, params);
} else if (ServerVariable.class.getName().equals(annotationName)) {
var variables = new LinkedHashMap<String, Map<CharSequence, Object>>();
for (Object o : a) {
var sv = (AnnotationValue<ServerVariable>) o;
sv.stringValue("name").ifPresent(name -> {
sv.stringValue(PROP_NAME).ifPresent(name -> {
Map<CharSequence, Object> map = toValueMap(sv.getValues(), context);
Object dv = map.get("defaultValue");
Object dv = map.get(PROP_DEFAULT_VALUE);
if (dv != null) {
map.put("default", dv);
map.put(PROP_DEFAULT, dv);
}
if (map.containsKey("allowableValues")) {
if (map.containsKey(PROP_ALLOWABLE_VALUES)) {
// The key in the generated openapi needs to be "enum"
map.put("enum", map.remove("allowableValues"));
map.put(PROP_ENUM, map.remove(PROP_ALLOWABLE_VALUES));
}
variables.put(name, map);
});
Expand Down Expand Up @@ -291,10 +305,10 @@ public static <T> T treeToValue(JsonNode jn, Class<T> clazz, VisitorContext cont

var finalValue = value;

resolveExtensions(jn).ifPresent(extensions -> BeanMap.of(finalValue).put("extensions", extensions));
String elType = jn.has("type") ? jn.get("type").textValue() : null;
String elFormat = jn.has("format") ? jn.get("format").textValue() : null;
JsonNode defaultValueNode = jn.get("defaultValue");
resolveExtensions(jn).ifPresent(extensions -> BeanMap.of(finalValue).put(PROP_EXTENSIONS, extensions));
String elType = jn.has(PROP_TYPE) ? jn.get(PROP_TYPE).textValue() : null;
String elFormat = jn.has(PROP_ONE_FORMAT) ? jn.get(PROP_ONE_FORMAT).textValue() : null;
JsonNode defaultValueNode = jn.get(PROP_DEFAULT_VALUE);
// fix for default value
Object defaultValue;
try {
Expand All @@ -305,10 +319,10 @@ public static <T> T treeToValue(JsonNode jn, Class<T> clazz, VisitorContext cont

BeanMap<T> beanMap = BeanMap.of(value);
if (defaultValue != null) {
beanMap.put("default", defaultValue);
beanMap.put(PROP_DEFAULT, defaultValue);
}

JsonNode allowableValuesNode = jn.get("allowableValues");
JsonNode allowableValuesNode = jn.get(PROP_ALLOWABLE_VALUES);
if (allowableValuesNode != null && allowableValuesNode.isArray()) {
var allowableValues = new ArrayList<>(allowableValuesNode.size());
for (JsonNode allowableValueNode : allowableValuesNode) {
Expand All @@ -321,7 +335,7 @@ public static <T> T treeToValue(JsonNode jn, Class<T> clazz, VisitorContext cont
allowableValues.add(allowableValueNode.textValue());
}
}
beanMap.put("allowableValues", allowableValues);
beanMap.put(PROP_ALLOWABLE_VALUES, allowableValues);
}

return value;
Expand Down Expand Up @@ -393,10 +407,10 @@ private static <T> T fixContentForGroovy(JsonNode parentNode, Class<T> clazz) th

var contentNode = parentNode.get("content");
if (contentNode != null) {
examples = deserMap("examples", contentNode, Example.class);
examples = deserMap(PROP_EXAMPLES, contentNode, Example.class);
encoding = deserMap("encoding", contentNode, Encoding.class);
extensions = deserMap("extensions", contentNode, Object.class);
var schemaNode = contentNode.get("schema");
extensions = deserMap(PROP_EXTENSIONS, contentNode, Object.class);
var schemaNode = contentNode.get(PROP_SCHEMA);
if (schemaNode != null) {
schema = CONVERT_JSON_MAPPER.treeToValue(schemaNode, Schema.class);
}
Expand All @@ -417,8 +431,8 @@ private static <T> T fixContentForGroovy(JsonNode parentNode, Class<T> clazz) th
}

if (content != null) {
var mediaType = content.get("schema");
content.remove("schema");
var mediaType = content.get(PROP_SCHEMA);
content.remove(PROP_SCHEMA);
if (mediaType == null) {
mediaType = new MediaType();
}
Expand Down Expand Up @@ -457,7 +471,7 @@ public static Object normalizeValue(String valueStr, String type, String format,

public static Optional<Map<String, Object>> resolveExtensions(JsonNode jn) {
try {
JsonNode extensionsNode = jn.get("extensions");
JsonNode extensionsNode = jn.get(PROP_EXTENSIONS);
if (extensionsNode != null) {
return Optional.ofNullable(CONVERT_JSON_MAPPER.convertValue(extensionsNode, MAP_TYPE_REFERENCE));
}
Expand All @@ -474,20 +488,20 @@ public static void addSecuritySchemes(OpenAPI openApi,

final Map<CharSequence, Object> map = toValueMap(securityRequirementAnnValue.getValues(), context);

var name = securityRequirementAnnValue.stringValue("name").orElse(null);
var name = securityRequirementAnnValue.stringValue(PROP_NAME).orElse(null);
if (StringUtils.isEmpty(name)) {
continue;
}
if (map.containsKey("paramName")) {
map.put("name", map.remove("paramName"));
map.put(PROP_NAME, map.remove("paramName"));
}

Utils.normalizeEnumValues(map, CollectionUtils.mapOf("type", SecurityScheme.Type.class, "in", SecurityScheme.In.class));
Utils.normalizeEnumValues(map, CollectionUtils.mapOf(PROP_TYPE, SecurityScheme.Type.class, PROP_IN, SecurityScheme.In.class));

var type = (String) map.get("type");
var type = (String) map.get(PROP_TYPE);
if (!SecurityScheme.Type.APIKEY.toString().equals(type)) {
removeAndWarnSecSchemeProp(map, "name", context, false);
removeAndWarnSecSchemeProp(map, "in", context);
removeAndWarnSecSchemeProp(map, PROP_NAME, context, false);
removeAndWarnSecSchemeProp(map, PROP_IN, context);
}
if (!SecurityScheme.Type.OAUTH2.toString().equals(type)) {
removeAndWarnSecSchemeProp(map, "flows", context);
Expand All @@ -508,20 +522,20 @@ public static void addSecuritySchemes(OpenAPI openApi,
}
}

if (map.containsKey("ref") || map.containsKey("$ref")) {
Object ref = map.get("ref");
if (map.containsKey(PROP_REF) || map.containsKey(PROP_$REF)) {
Object ref = map.get(PROP_REF);
if (ref == null) {
ref = map.get("$ref");
ref = map.get(PROP_$REF);
}
map.clear();
map.put("$ref", ref);
map.put(PROP_$REF, ref);
}

try {
JsonNode node = toJson(map, context);
SecurityScheme securityScheme = ConvertUtils.treeToValue(node, SecurityScheme.class, context);
if (securityScheme != null) {
resolveExtensions(node).ifPresent(extensions -> BeanMap.of(securityScheme).put("extensions", extensions));
resolveExtensions(node).ifPresent(extensions -> BeanMap.of(securityScheme).put(PROP_EXTENSIONS, extensions));
resolveComponents(openApi).addSecuritySchemes(name, securityScheme);
}
} catch (JsonProcessingException e) {
Expand All @@ -536,7 +550,7 @@ private static void removeAndWarnSecSchemeProp(Map<CharSequence, Object> map, St

private static void removeAndWarnSecSchemeProp(Map<CharSequence, Object> map, String prop, VisitorContext context, boolean withWarn) {
if (map.containsKey(prop) && withWarn) {
warn("'" + prop + "' property can't set for securityScheme with type " + map.get("type") + ". Skip it", context);
warn("'" + prop + "' property can't set for securityScheme with type " + map.get(PROP_TYPE) + ". Skip it", context);
}
map.remove(prop);
}
Expand All @@ -553,7 +567,7 @@ private static void removeAndWarnSecSchemeProp(Map<CharSequence, Object> map, St
* @return converted object.
*/
public static SecurityRequirement mapToSecurityRequirement(AnnotationValue<io.swagger.v3.oas.annotations.security.SecurityRequirement> r) {
String name = r.getRequiredValue("name", String.class);
String name = r.getRequiredValue(PROP_NAME, String.class);
List<String> scopes = Arrays.asList(r.stringValues("scopes"));
var securityRequirement = new SecurityRequirement();
securityRequirement.addList(name, scopes);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,10 @@
*/
package io.micronaut.openapi.visitor;

import java.io.File;
import java.io.InputStream;
import java.lang.annotation.Annotation;
import java.nio.ByteBuffer;
import java.security.Principal;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.Future;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonView;
import io.micronaut.core.annotation.AnnotationMetadata;
import io.micronaut.core.annotation.AnnotationValue;
import io.micronaut.core.annotation.Internal;
Expand All @@ -44,9 +36,20 @@
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Schema;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.io.File;
import java.io.InputStream;
import java.lang.annotation.Annotation;
import java.nio.ByteBuffer;
import java.security.Principal;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.Future;

import static io.micronaut.openapi.visitor.ConfigUtils.isJsonViewEnabled;
import static io.micronaut.openapi.visitor.OpenApiModelProp.PROP_HIDDEN;

/**
* Some util methods.
Expand Down Expand Up @@ -89,21 +92,6 @@ public final class ElementUtils {
private ElementUtils() {
}

/**
* Returns true if classElement is a JavaClassElement.
*
* @param classElement A ClassElement.
* @param context The context.
*
* @return true if classElement is a JavaClassElement.
*/
public static boolean isJavaElement(ClassElement classElement, VisitorContext context) {
return classElement != null
&& "io.micronaut.annotation.processing.visitor.JavaClassElement".equals(classElement.getClass().getName())
&& context != null
&& "io.micronaut.annotation.processing.visitor.JavaVisitorContext".equals(context.getClass().getName());
}

/**
* Checks Nullable annotations / optional type to understand that the element can be null.
*
Expand Down Expand Up @@ -215,13 +203,13 @@ private static boolean findAnyAssignable(ClassElement type, List<String> typeNam
public static boolean isIgnoredParameter(TypedElement parameter) {

AnnotationValue<Schema> schemaAnn = parameter.getAnnotation(Schema.class);
boolean isHidden = schemaAnn != null && schemaAnn.booleanValue("hidden").orElse(false);
boolean isHidden = schemaAnn != null && schemaAnn.booleanValue(PROP_HIDDEN).orElse(false);

return isHidden
|| parameter.isAnnotationPresent(Hidden.class)
|| parameter.isAnnotationPresent(JsonIgnore.class)
|| parameter.isAnnotationPresent(Header.class) && parameter.getType().isAssignable(Map.class)
|| parameter.booleanValue(Parameter.class, "hidden").orElse(false)
|| parameter.booleanValue(Parameter.class, PROP_HIDDEN).orElse(false)
|| parameter.hasAnnotation("io.micronaut.session.annotation.SessionValue")
|| parameter.hasAnnotation("org.springframework.web.bind.annotation.SessionAttribute")
|| parameter.hasAnnotation("org.springframework.web.bind.annotation.SessionAttributes")
Expand Down Expand Up @@ -395,4 +383,18 @@ private static MethodElement getCreatorConstructor(ClassElement classEl) {
Utils.getCreatorConstructorsCache().put(classEl.getName(), creatorConstructor);
return creatorConstructor;
}

public static ClassElement getJsonViewClass(Element element, VisitorContext context) {
if (!isJsonViewEnabled(context)) {
return null;
}
var jsonViewAnn = element.findAnnotation(JsonView.class).orElse(null);
if (jsonViewAnn != null) {
String jsonViewClassName = jsonViewAnn.stringValue().orElse(null);
if (jsonViewClassName != null) {
return ContextUtils.getClassElement(jsonViewClassName, context);
}
}
return null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -203,8 +203,8 @@ private static List<Tag> parseTags(String stringTagsStr) {
}

private static String parsePath(String path) {
if (StringUtils.isNotEmpty(path) && !path.endsWith("/")) {
return path + "/";
if (StringUtils.isNotEmpty(path) && !path.endsWith(StringUtil.SLASH)) {
return path + StringUtil.SLASH;
} else {
return path;
}
Expand Down
Loading

0 comments on commit f80c0eb

Please sign in to comment.