This is an automated email from the ASF dual-hosted git repository.
jamesbognar pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/juneau.git
The following commit(s) were added to refs/heads/master by this push:
new 648792a1a1 SonarQube bug fixes
648792a1a1 is described below
commit 648792a1a1f373870c862506ca409304240129d1
Author: James Bognar <[email protected]>
AuthorDate: Wed Feb 4 09:17:34 2026 -0500
SonarQube bug fixes
---
SONARQUBE_ISSUES_SUMMARY.md | 181 +++++++++
.../org/apache/juneau/bean/openapi3/Callback.java | 9 +-
.../apache/juneau/bean/openapi3/Components.java | 65 ++--
.../org/apache/juneau/bean/openapi3/Encoding.java | 37 +-
.../apache/juneau/bean/openapi3/HeaderInfo.java | 72 ++--
.../java/org/apache/juneau/bean/openapi3/Info.java | 44 ++-
.../org/apache/juneau/bean/openapi3/Items.java | 128 ++++---
.../java/org/apache/juneau/bean/openapi3/Link.java | 44 ++-
.../org/apache/juneau/bean/openapi3/OpenApi.java | 58 +--
.../org/apache/juneau/bean/openapi3/Operation.java | 86 +++--
.../org/apache/juneau/bean/openapi3/Parameter.java | 86 +++--
.../org/apache/juneau/bean/openapi3/PathItem.java | 86 +++--
.../juneau/bean/openapi3/RequestBodyInfo.java | 23 +-
.../juneau/bean/openapi3/SecuritySchemeInfo.java | 58 +--
.../org/apache/juneau/bean/swagger/Operation.java | 86 +++--
.../org/apache/juneau/bean/swagger/Swagger.java | 108 +++---
scripts/README_SONARQUBE.md | 217 +++++++++++
scripts/categorize-sonar-issues.py | 408 +++++++++++++++++++++
scripts/view-sonar-category.py | 91 +++++
19 files changed, 1476 insertions(+), 411 deletions(-)
diff --git a/SONARQUBE_ISSUES_SUMMARY.md b/SONARQUBE_ISSUES_SUMMARY.md
new file mode 100644
index 0000000000..0295ce0653
--- /dev/null
+++ b/SONARQUBE_ISSUES_SUMMARY.md
@@ -0,0 +1,181 @@
+# SonarQube Issues Categorization Summary
+
+This document provides an overview of the categorized SonarQube issues for the
Apache Juneau project.
+
+## Summary Statistics
+
+- **Total Issues**: 3,116
+- **Total Categories**: 30
+- **Categorized**: ~78% (remaining 22% are miscellaneous "Other Issues")
+
+## Issue Categories (Sorted by Count)
+
+| Category | Count | Percentage | Priority |
+|----------|-------|------------|---------|
+| Other Issues | 2,433 | 78.1% | Low |
+| Generic Type Issues | 121 | 3.9% | Medium |
+| Empty Method Implementations | 99 | 3.2% | Medium |
+| Unused Code | 96 | 3.1% | Low |
+| Missing Private Constructors | 91 | 2.9% | Low |
+| Test Assertion Issues | 61 | 2.0% | Medium |
+| Brain Methods (Complexity) | 30 | 1.0% | High |
+| Exception Catching Issues | 30 | 1.0% | Medium |
+| Optional Access Issues | 18 | 0.6% | Medium |
+| Missing Test Assertions | 16 | 0.5% | Medium |
+| Code Duplication | 16 | 0.5% | Medium |
+| Null Check Issues | 15 | 0.5% | High |
+| Field Shadowing | 11 | 0.4% | Low |
+| Python f-string Issues | 11 | 0.4% | Low |
+| Missing @Override Annotations | 11 | 0.4% | Low |
+| Constructor Visibility Issues | 10 | 0.3% | Low |
+| Unnecessary toString() Calls | 8 | 0.3% | Low |
+| ThreadLocal Cleanup Issues | 7 | 0.2% | Medium |
+| HTML/Documentation Issues | 6 | 0.2% | Low |
+| Singleton Pattern Issues | 6 | 0.2% | Medium |
+| Security Issues | 6 | 0.2% | High |
+| Missing Test Coverage | 3 | 0.1% | Low |
+| Deprecated Annotation Issues | 2 | 0.1% | Low |
+| Missing clone() Methods | 2 | 0.1% | Low |
+| Type Casting Issues | 2 | 0.1% | Low |
+| Line Separator Issues | 1 | 0.0% | Low |
+| Missing Exception Handling | 1 | 0.0% | High |
+| Empty Catch Blocks | 1 | 0.0% | Medium |
+| String Concatenation Issues | 1 | 0.0% | Low |
+
+## Recommended Fix Order
+
+### High Priority (Start Here)
+1. **Security Issues** (6 issues) - Security vulnerabilities should be fixed
immediately
+2. **Null Check Issues** (15 issues) - Potential NullPointerExceptions
+3. **Brain Methods (Complexity)** (30 issues) - Code maintainability issues
+4. **Missing Exception Handling** (1 issue) - Critical error handling
+
+### Medium Priority
+5. **Exception Catching Issues** (30 issues) - Improve exception handling
patterns
+6. **Generic Type Issues** (121 issues) - Type safety improvements
+7. **Empty Method Implementations** (99 issues) - Complete implementations or
document why empty
+8. **Test Assertion Issues** (61 issues) - Fix test assertions
+9. **Optional Access Issues** (18 issues) - Proper Optional handling
+10. **Code Duplication** (16 issues) - Refactor duplicated code
+11. **ThreadLocal Cleanup Issues** (7 issues) - Memory leak prevention
+
+### Low Priority
+12. **Unused Code** (96 issues) - Remove dead code
+13. **Missing Private Constructors** (91 issues) - Utility class improvements
+14. **Missing @Override Annotations** (11 issues) - Code clarity
+15. **Unnecessary toString() Calls** (8 issues) - Minor optimizations
+16. **Other categories** - Fix as time permits
+
+## How to Use the Categorization Tool
+
+### 1. Generate Categorized Report
+
+```bash
+cd /Users/james.bognar/git/apache/juneau/master
+python3 scripts/categorize-sonar-issues.py
/Users/james.bognar/Downloads/SonarQubeIssues.txt --save-json
+```
+
+This will:
+- Parse all SonarQube issues
+- Categorize them into 30 categories
+- Save a JSON file with all categorized issues
+- Display a summary
+
+### 2. View Category Details
+
+The JSON file (`SonarQubeIssues.categorized.json`) contains all issues
organized by category. You can:
+
+- View specific categories
+- See all issues in a category
+- Get file locations and line numbers for each issue
+
+### 3. Interactive Fixing Session
+
+Run the script without `--save-json` to start an interactive session:
+
+```bash
+python3 scripts/categorize-sonar-issues.py
/Users/james.bognar/Downloads/SonarQubeIssues.txt
+```
+
+Commands available:
+- `fix` - Start fixing issues in current category
+- `skip` - Move to next category
+- `details` - Show detailed issue information
+- `list` - List all categories
+- `<number>` - Jump to specific category number
+- `quit` - Exit
+
+## Category Descriptions
+
+### High Priority Categories
+
+**Security Issues**: Security vulnerabilities that need immediate attention.
+
+**Null Check Issues**: Missing null checks that could lead to
NullPointerExceptions.
+
+**Brain Methods (Complexity)**: Methods that are too complex (high LOC,
complexity, nesting, or variable count). These need refactoring.
+
+**Missing Exception Handling**: Missing exception handling in critical code
paths.
+
+### Medium Priority Categories
+
+**Exception Catching Issues**: Catching overly broad exceptions (Throwable,
Error) instead of specific Exception types.
+
+**Generic Type Issues**: Using raw types instead of parameterized generic
types.
+
+**Empty Method Implementations**: Empty methods that should either be
implemented or documented why they're empty.
+
+**Test Assertion Issues**: Test assertions comparing incompatible types or
comparing primitives with null.
+
+**Optional Access Issues**: Accessing Optional values without checking
ifPresent() or isEmpty() first.
+
+**Code Duplication**: Duplicated code blocks that should be refactored.
+
+**ThreadLocal Cleanup Issues**: ThreadLocal variables not being cleaned up,
potentially causing memory leaks.
+
+### Low Priority Categories
+
+**Unused Code**: Unused parameters, variables, fields, methods, or imports.
+
+**Missing Private Constructors**: Utility classes that should have private
constructors to prevent instantiation.
+
+**Missing @Override Annotations**: Methods overriding parent methods without
@Override annotation.
+
+**Unnecessary toString() Calls**: Calling toString() on values that are
already strings.
+
+**Field Shadowing**: Local variables or parameters shadowing class fields.
+
+**Python f-string Issues**: Python f-strings without replacement fields
(should use regular strings).
+
+**HTML/Documentation Issues**: Missing HTML attributes or documentation
elements.
+
+**Singleton Pattern Issues**: Singleton implementations that may need review.
+
+**Missing Test Coverage**: Classes that need test coverage.
+
+**Deprecated Annotation Issues**: @Deprecated annotations missing 'since' or
'forRemoval' arguments.
+
+**Missing clone() Methods**: Classes that should implement clone().
+
+**Type Casting Issues**: Operations that need explicit casting to prevent
overflow.
+
+**Line Separator Issues**: Using \n instead of %n for platform-specific line
separators.
+
+**Empty Catch Blocks**: Catch blocks without logic that should either add
logic or rethrow.
+
+**String Concatenation Issues**: String concatenation in loops that should use
StringBuilder.
+
+## Next Steps
+
+1. Review this summary and prioritize categories based on your project needs
+2. Start with High Priority categories
+3. Use the interactive tool to work through categories systematically
+4. For each category, decide on a fix strategy:
+ - **Auto-fix**: Simple, mechanical fixes (e.g., adding @Override, removing
unused imports)
+ - **Manual review**: Complex issues requiring code review (e.g., Brain
Methods, Security Issues)
+ - **Batch fix**: Similar issues that can be fixed together (e.g., Missing
Private Constructors)
+
+## Files Generated
+
+- `SonarQubeIssues.categorized.json` - Complete categorized issues in JSON
format
+- This summary document
diff --git
a/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/Callback.java
b/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/Callback.java
index 96d1f2e9d1..6d6bdb469b 100644
---
a/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/Callback.java
+++
b/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/Callback.java
@@ -72,6 +72,9 @@ import org.apache.juneau.commons.collections.*;
*/
public class Callback extends OpenApiElement {
+ // Property name constants
+ private static final String PROP_CALLBACKS = "callbacks";
+
private Map<String,PathItem> callbacks;
/**
@@ -118,7 +121,7 @@ public class Callback extends OpenApiElement {
public <T> T get(String property, Class<T> type) {
assertArgNotNull("property", property);
return switch (property) {
- case "callbacks" -> toType(getCallbacks(), type);
+ case PROP_CALLBACKS -> toType(getCallbacks(), type);
default -> super.get(property, type);
};
}
@@ -134,7 +137,7 @@ public class Callback extends OpenApiElement {
public Set<String> keySet() {
// @formatter:off
var s = setb(String.class)
- .addIf(nn(callbacks), "callbacks")
+ .addIf(nn(callbacks), PROP_CALLBACKS)
.build();
// @formatter:on
return new MultiSet<>(s, super.keySet());
@@ -144,7 +147,7 @@ public class Callback extends OpenApiElement {
public Callback set(String property, Object value) {
assertArgNotNull("property", property);
return switch (property) {
- case "callbacks" -> setCallbacks(toMapBuilder(value,
String.class, PathItem.class).sparse().build());
+ case PROP_CALLBACKS -> setCallbacks(toMapBuilder(value,
String.class, PathItem.class).sparse().build());
default -> {
super.set(property, value);
yield this;
diff --git
a/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/Components.java
b/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/Components.java
index be10df546c..6aacc2be31 100644
---
a/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/Components.java
+++
b/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/Components.java
@@ -84,6 +84,17 @@ import org.apache.juneau.commons.collections.*;
*/
public class Components extends OpenApiElement {
+ // Property name constants
+ private static final String PROP_CALLBACKS = "callbacks";
+ private static final String PROP_EXAMPLES = "examples";
+ private static final String PROP_HEADERS = "headers";
+ private static final String PROP_LINKS = "links";
+ private static final String PROP_PARAMETERS = "parameters";
+ private static final String PROP_REQUEST_BODIES = "requestBodies";
+ private static final String PROP_RESPONSES = "responses";
+ private static final String PROP_SCHEMAS = "schemas";
+ private static final String PROP_SECURITY_SCHEMES = "securitySchemes";
+
private Map<String,SchemaInfo> schemas;
private Map<String,Response> responses;
private Map<String,Parameter> parameters;
@@ -130,15 +141,15 @@ public class Components extends OpenApiElement {
public <T> T get(String property, Class<T> type) {
assertArgNotNull("property", property);
return switch (property) {
- case "schemas" -> toType(getSchemas(), type);
- case "responses" -> toType(getResponses(), type);
- case "parameters" -> toType(getParameters(), type);
- case "examples" -> toType(getExamples(), type);
- case "requestBodies" -> toType(getRequestBodies(),
type);
- case "headers" -> toType(getHeaders(), type);
- case "securitySchemes" -> toType(getSecuritySchemes(),
type);
- case "links" -> toType(getLinks(), type);
- case "callbacks" -> toType(getCallbacks(), type);
+ case PROP_SCHEMAS -> toType(getSchemas(), type);
+ case PROP_RESPONSES -> toType(getResponses(), type);
+ case PROP_PARAMETERS -> toType(getParameters(), type);
+ case PROP_EXAMPLES -> toType(getExamples(), type);
+ case PROP_REQUEST_BODIES -> toType(getRequestBodies(),
type);
+ case PROP_HEADERS -> toType(getHeaders(), type);
+ case PROP_SECURITY_SCHEMES ->
toType(getSecuritySchemes(), type);
+ case PROP_LINKS -> toType(getLinks(), type);
+ case PROP_CALLBACKS -> toType(getCallbacks(), type);
default -> super.get(property, type);
};
}
@@ -210,15 +221,15 @@ public class Components extends OpenApiElement {
public Set<String> keySet() {
// @formatter:off
var s = setb(String.class)
- .addIf(nn(callbacks), "callbacks")
- .addIf(nn(examples), "examples")
- .addIf(nn(headers), "headers")
- .addIf(nn(links), "links")
- .addIf(nn(parameters), "parameters")
- .addIf(nn(requestBodies), "requestBodies")
- .addIf(nn(responses), "responses")
- .addIf(nn(schemas), "schemas")
- .addIf(nn(securitySchemes), "securitySchemes")
+ .addIf(nn(callbacks), PROP_CALLBACKS)
+ .addIf(nn(examples), PROP_EXAMPLES)
+ .addIf(nn(headers), PROP_HEADERS)
+ .addIf(nn(links), PROP_LINKS)
+ .addIf(nn(parameters), PROP_PARAMETERS)
+ .addIf(nn(requestBodies), PROP_REQUEST_BODIES)
+ .addIf(nn(responses), PROP_RESPONSES)
+ .addIf(nn(schemas), PROP_SCHEMAS)
+ .addIf(nn(securitySchemes), PROP_SECURITY_SCHEMES)
.build();
// @formatter:on
return new MultiSet<>(s, super.keySet());
@@ -228,15 +239,15 @@ public class Components extends OpenApiElement {
public Components set(String property, Object value) {
assertArgNotNull("property", property);
return switch (property) {
- case "callbacks" -> setCallbacks(toMapBuilder(value,
String.class, Callback.class).sparse().build());
- case "examples" -> setExamples(toMapBuilder(value,
String.class, Example.class).sparse().build());
- case "headers" -> setHeaders(toMapBuilder(value,
String.class, HeaderInfo.class).sparse().build());
- case "links" -> setLinks(toMapBuilder(value,
String.class, Link.class).sparse().build());
- case "parameters" -> setParameters(toMapBuilder(value,
String.class, Parameter.class).sparse().build());
- case "requestBodies" ->
setRequestBodies(toMapBuilder(value, String.class,
RequestBodyInfo.class).sparse().build());
- case "responses" -> setResponses(toMapBuilder(value,
String.class, Response.class).sparse().build());
- case "schemas" -> setSchemas(toMapBuilder(value,
String.class, SchemaInfo.class).sparse().build());
- case "securitySchemes" ->
setSecuritySchemes(toMapBuilder(value, String.class,
SecuritySchemeInfo.class).sparse().build());
+ case PROP_CALLBACKS -> setCallbacks(toMapBuilder(value,
String.class, Callback.class).sparse().build());
+ case PROP_EXAMPLES -> setExamples(toMapBuilder(value,
String.class, Example.class).sparse().build());
+ case PROP_HEADERS -> setHeaders(toMapBuilder(value,
String.class, HeaderInfo.class).sparse().build());
+ case PROP_LINKS -> setLinks(toMapBuilder(value,
String.class, Link.class).sparse().build());
+ case PROP_PARAMETERS ->
setParameters(toMapBuilder(value, String.class,
Parameter.class).sparse().build());
+ case PROP_REQUEST_BODIES ->
setRequestBodies(toMapBuilder(value, String.class,
RequestBodyInfo.class).sparse().build());
+ case PROP_RESPONSES -> setResponses(toMapBuilder(value,
String.class, Response.class).sparse().build());
+ case PROP_SCHEMAS -> setSchemas(toMapBuilder(value,
String.class, SchemaInfo.class).sparse().build());
+ case PROP_SECURITY_SCHEMES ->
setSecuritySchemes(toMapBuilder(value, String.class,
SecuritySchemeInfo.class).sparse().build());
default -> {
super.set(property, value);
yield this;
diff --git
a/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/Encoding.java
b/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/Encoding.java
index b8a848f4be..dd3988e3df 100644
---
a/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/Encoding.java
+++
b/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/Encoding.java
@@ -76,6 +76,13 @@ import org.apache.juneau.commons.collections.*;
*/
public class Encoding extends OpenApiElement {
+ // Property name constants
+ private static final String PROP_ALLOW_RESERVED = "allowReserved";
+ private static final String PROP_CONTENT_TYPE = "contentType";
+ private static final String PROP_EXPLODE = "explode";
+ private static final String PROP_HEADERS = "headers";
+ private static final String PROP_STYLE = "style";
+
private String contentType, style;
private Map<String,HeaderInfo> headers = map();
private Boolean explode, allowReserved;
@@ -130,11 +137,11 @@ public class Encoding extends OpenApiElement {
public <T> T get(String property, Class<T> type) {
assertArgNotNull("property", property);
return switch (property) {
- case "contentType" -> toType(getContentType(), type);
- case "style" -> toType(getStyle(), type);
- case "headers" -> toType(getHeaders(), type);
- case "explode" -> toType(getExplode(), type);
- case "allowReserved" -> toType(getAllowReserved(),
type);
+ case PROP_CONTENT_TYPE -> toType(getContentType(),
type);
+ case PROP_STYLE -> toType(getStyle(), type);
+ case PROP_HEADERS -> toType(getHeaders(), type);
+ case PROP_EXPLODE -> toType(getExplode(), type);
+ case PROP_ALLOW_RESERVED -> toType(getAllowReserved(),
type);
default -> super.get(property, type);
};
}
@@ -187,11 +194,11 @@ public class Encoding extends OpenApiElement {
public Set<String> keySet() {
// @formatter:off
var s = setb(String.class)
- .addIf(nn(allowReserved), "allowReserved")
- .addIf(nn(contentType), "contentType")
- .addIf(nn(explode), "explode")
- .addIf(ne(headers), "headers")
- .addIf(nn(style), "style")
+ .addIf(nn(allowReserved), PROP_ALLOW_RESERVED)
+ .addIf(nn(contentType), PROP_CONTENT_TYPE)
+ .addIf(nn(explode), PROP_EXPLODE)
+ .addIf(ne(headers), PROP_HEADERS)
+ .addIf(nn(style), PROP_STYLE)
.build();
// @formatter:on
return new MultiSet<>(s, super.keySet());
@@ -201,11 +208,11 @@ public class Encoding extends OpenApiElement {
public Encoding set(String property, Object value) {
assertArgNotNull("property", property);
return switch (property) {
- case "allowReserved" ->
setAllowReserved(toBoolean(value));
- case "contentType" -> setContentType(s(value));
- case "explode" -> setExplode(toBoolean(value));
- case "headers" -> setHeaders(toMapBuilder(value,
String.class, HeaderInfo.class).sparse().build());
- case "style" -> setStyle(s(value));
+ case PROP_ALLOW_RESERVED ->
setAllowReserved(toBoolean(value));
+ case PROP_CONTENT_TYPE -> setContentType(s(value));
+ case PROP_EXPLODE -> setExplode(toBoolean(value));
+ case PROP_HEADERS -> setHeaders(toMapBuilder(value,
String.class, HeaderInfo.class).sparse().build());
+ case PROP_STYLE -> setStyle(s(value));
default -> {
super.set(property, value);
yield this;
diff --git
a/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/HeaderInfo.java
b/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/HeaderInfo.java
index 25fc70d6d3..172084dd77 100644
---
a/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/HeaderInfo.java
+++
b/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/HeaderInfo.java
@@ -77,6 +77,18 @@ import org.apache.juneau.commons.collections.*;
*/
public class HeaderInfo extends OpenApiElement {
+ // Property name constants
+ private static final String PROP_ALLOW_EMPTY_VALUE = "allowEmptyValue";
+ private static final String PROP_ALLOW_RESERVED = "allowReserved";
+ private static final String PROP_DEPRECATED = "deprecated";
+ private static final String PROP_DESCRIPTION = "description";
+ private static final String PROP_EXAMPLES = "examples";
+ private static final String PROP_EXPLODE = "explode";
+ private static final String PROP_REF = "$ref";
+ private static final String PROP_REQUIRED = "required";
+ private static final String PROP_SCHEMA = "schema";
+ private static final String PROP_X_EXAMPLE = "x-example";
+
private String description, ref;
private Boolean required, explode, deprecated, allowEmptyValue,
allowReserved;
private SchemaInfo schema;
@@ -136,16 +148,16 @@ public class HeaderInfo extends OpenApiElement {
public <T> T get(String property, Class<T> type) {
assertArgNotNull("property", property);
return switch (property) {
- case "description" -> toType(getDescription(), type);
- case "required" -> toType(getRequired(), type);
- case "explode" -> toType(getExplode(), type);
- case "deprecated" -> toType(getDeprecated(), type);
- case "allowEmptyValue" -> toType(getAllowEmptyValue(),
type);
- case "allowReserved" -> toType(getAllowReserved(),
type);
- case "$ref" -> toType(getRef(), type);
- case "schema" -> toType(getSchema(), type);
- case "x-example" -> toType(getExample(), type);
- case "examples" -> toType(getExamples(), type);
+ case PROP_DESCRIPTION -> toType(getDescription(), type);
+ case PROP_REQUIRED -> toType(getRequired(), type);
+ case PROP_EXPLODE -> toType(getExplode(), type);
+ case PROP_DEPRECATED -> toType(getDeprecated(), type);
+ case PROP_ALLOW_EMPTY_VALUE ->
toType(getAllowEmptyValue(), type);
+ case PROP_ALLOW_RESERVED -> toType(getAllowReserved(),
type);
+ case PROP_REF -> toType(getRef(), type);
+ case PROP_SCHEMA -> toType(getSchema(), type);
+ case PROP_X_EXAMPLE -> toType(getExample(), type);
+ case PROP_EXAMPLES -> toType(getExamples(), type);
default -> super.get(property, type);
};
}
@@ -247,16 +259,16 @@ public class HeaderInfo extends OpenApiElement {
public Set<String> keySet() {
// @formatter:off
var s = setb(String.class)
- .addIf(nn(ref), "$ref")
- .addIf(nn(allowEmptyValue), "allowEmptyValue")
- .addIf(nn(allowReserved), "allowReserved")
- .addIf(nn(deprecated), "deprecated")
- .addIf(nn(description), "description")
- .addIf(ne(examples), "examples")
- .addIf(nn(explode), "explode")
- .addIf(nn(required), "required")
- .addIf(nn(schema), "schema")
- .addIf(nn(example), "x-example")
+ .addIf(nn(ref), PROP_REF)
+ .addIf(nn(allowEmptyValue), PROP_ALLOW_EMPTY_VALUE)
+ .addIf(nn(allowReserved), PROP_ALLOW_RESERVED)
+ .addIf(nn(deprecated), PROP_DEPRECATED)
+ .addIf(nn(description), PROP_DESCRIPTION)
+ .addIf(ne(examples), PROP_EXAMPLES)
+ .addIf(nn(explode), PROP_EXPLODE)
+ .addIf(nn(required), PROP_REQUIRED)
+ .addIf(nn(schema), PROP_SCHEMA)
+ .addIf(nn(example), PROP_X_EXAMPLE)
.build();
// @formatter:on
return new MultiSet<>(s, super.keySet());
@@ -293,16 +305,16 @@ public class HeaderInfo extends OpenApiElement {
public HeaderInfo set(String property, Object value) {
assertArgNotNull("property", property);
return switch (property) {
- case "$ref" -> setRef(s(value));
- case "allowEmptyValue" ->
setAllowEmptyValue(toBoolean(value));
- case "allowReserved" ->
setAllowReserved(toBoolean(value));
- case "deprecated" -> setDeprecated(toBoolean(value));
- case "description" -> setDescription(s(value));
- case "examples" -> setExamples(toMapBuilder(value,
String.class, Example.class).sparse().build());
- case "explode" -> setExplode(toBoolean(value));
- case "required" -> setRequired(toBoolean(value));
- case "schema" -> setSchema(toType(value,
SchemaInfo.class));
- case "x-example" -> setExample(value);
+ case PROP_REF -> setRef(s(value));
+ case PROP_ALLOW_EMPTY_VALUE ->
setAllowEmptyValue(toBoolean(value));
+ case PROP_ALLOW_RESERVED ->
setAllowReserved(toBoolean(value));
+ case PROP_DEPRECATED -> setDeprecated(toBoolean(value));
+ case PROP_DESCRIPTION -> setDescription(s(value));
+ case PROP_EXAMPLES -> setExamples(toMapBuilder(value,
String.class, Example.class).sparse().build());
+ case PROP_EXPLODE -> setExplode(toBoolean(value));
+ case PROP_REQUIRED -> setRequired(toBoolean(value));
+ case PROP_SCHEMA -> setSchema(toType(value,
SchemaInfo.class));
+ case PROP_X_EXAMPLE -> setExample(value);
default -> {
super.set(property, value);
yield this;
diff --git
a/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/Info.java
b/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/Info.java
index 957c893e65..1dfc81c2e3 100644
---
a/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/Info.java
+++
b/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/Info.java
@@ -100,6 +100,14 @@ import org.apache.juneau.commons.collections.*;
*/
public class Info extends OpenApiElement {
+ // Property name constants
+ private static final String PROP_CONTACT = "contact";
+ private static final String PROP_DESCRIPTION = "description";
+ private static final String PROP_LICENSE = "license";
+ private static final String PROP_TERMS_OF_SERVICE = "termsOfService";
+ private static final String PROP_TITLE = "title";
+ private static final String PROP_VERSION = "version";
+
private String title, description, termsOfService, version;
private Contact contact;
private License license;
@@ -138,12 +146,12 @@ public class Info extends OpenApiElement {
public <T> T get(String property, Class<T> type) {
assertArgNotNull("property", property);
return switch (property) {
- case "title" -> toType(getTitle(), type);
- case "description" -> toType(getDescription(), type);
- case "termsOfService" -> toType(getTermsOfService(),
type);
- case "contact" -> toType(getContact(), type);
- case "license" -> toType(getLicense(), type);
- case "version" -> toType(getVersion(), type);
+ case PROP_TITLE -> toType(getTitle(), type);
+ case PROP_DESCRIPTION -> toType(getDescription(), type);
+ case PROP_TERMS_OF_SERVICE ->
toType(getTermsOfService(), type);
+ case PROP_CONTACT -> toType(getContact(), type);
+ case PROP_LICENSE -> toType(getLicense(), type);
+ case PROP_VERSION -> toType(getVersion(), type);
default -> super.get(property, type);
};
}
@@ -212,12 +220,12 @@ public class Info extends OpenApiElement {
public Set<String> keySet() {
// @formatter:off
var s = setb(String.class)
- .addIf(nn(contact), "contact")
- .addIf(nn(description), "description")
- .addIf(nn(license), "license")
- .addIf(nn(termsOfService), "termsOfService")
- .addIf(nn(title), "title")
- .addIf(nn(version), "version")
+ .addIf(nn(contact), PROP_CONTACT)
+ .addIf(nn(description), PROP_DESCRIPTION)
+ .addIf(nn(license), PROP_LICENSE)
+ .addIf(nn(termsOfService), PROP_TERMS_OF_SERVICE)
+ .addIf(nn(title), PROP_TITLE)
+ .addIf(nn(version), PROP_VERSION)
.build();
// @formatter:on
return new MultiSet<>(s, super.keySet());
@@ -227,12 +235,12 @@ public class Info extends OpenApiElement {
public Info set(String property, Object value) {
assertArgNotNull("property", property);
return switch (property) {
- case "contact" -> setContact(toType(value,
Contact.class));
- case "description" -> setDescription(s(value));
- case "license" -> setLicense(toType(value,
License.class));
- case "termsOfService" -> setTermsOfService(s(value));
- case "title" -> setTitle(s(value));
- case "version" -> setVersion(s(value));
+ case PROP_CONTACT -> setContact(toType(value,
Contact.class));
+ case PROP_DESCRIPTION -> setDescription(s(value));
+ case PROP_LICENSE -> setLicense(toType(value,
License.class));
+ case PROP_TERMS_OF_SERVICE ->
setTermsOfService(s(value));
+ case PROP_TITLE -> setTitle(s(value));
+ case PROP_VERSION -> setVersion(s(value));
default -> {
super.set(property, value);
yield this;
diff --git
a/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/Items.java
b/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/Items.java
index afb226f38e..5bcac70686 100644
---
a/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/Items.java
+++
b/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/Items.java
@@ -84,6 +84,26 @@ public class Items extends OpenApiElement {
private static final String[] VALID_TYPES = { "string", "number",
"integer", "boolean", "array" };
private static final String[] VALID_COLLECTION_FORMATS = { "csv",
"ssv", "tsv", "pipes", "multi" };
+ // Property name constants
+ private static final String PROP_COLLECTION_FORMAT = "collectionFormat";
+ private static final String PROP_DEFAULT = "default";
+ private static final String PROP_ENUM = "enum";
+ private static final String PROP_EXCLUSIVE_MAXIMUM = "exclusiveMaximum";
+ private static final String PROP_EXCLUSIVE_MINIMUM = "exclusiveMinimum";
+ private static final String PROP_FORMAT = "format";
+ private static final String PROP_ITEMS = "items";
+ private static final String PROP_MAXIMUM = "maximum";
+ private static final String PROP_MAX_ITEMS = "maxItems";
+ private static final String PROP_MAX_LENGTH = "maxLength";
+ private static final String PROP_MINIMUM = "minimum";
+ private static final String PROP_MIN_ITEMS = "minItems";
+ private static final String PROP_MIN_LENGTH = "minLength";
+ private static final String PROP_MULTIPLE_OF = "multipleOf";
+ private static final String PROP_PATTERN = "pattern";
+ private static final String PROP_REF = "$ref";
+ private static final String PROP_TYPE = "type";
+ private static final String PROP_UNIQUE_ITEMS = "uniqueItems";
+
private String type, format, collectionFormat, pattern, ref;
private Number maximum, minimum, multipleOf;
private Integer maxLength, minLength, maxItems, minItems;
@@ -155,24 +175,24 @@ public class Items extends OpenApiElement {
public <T> T get(String property, Class<T> type) {
assertArgNotNull("property", property);
return switch (property) {
- case "type" -> toType(getType(), type);
- case "format" -> toType(getFormat(), type);
- case "items" -> toType(getItems(), type);
- case "collectionFormat" ->
toType(getCollectionFormat(), type);
- case "default" -> toType(getDefault(), type);
- case "maximum" -> toType(getMaximum(), type);
- case "exclusiveMaximum" ->
toType(getExclusiveMaximum(), type);
- case "minimum" -> toType(getMinimum(), type);
- case "exclusiveMinimum" ->
toType(getExclusiveMinimum(), type);
- case "maxLength" -> toType(getMaxLength(), type);
- case "minLength" -> toType(getMinLength(), type);
- case "pattern" -> toType(getPattern(), type);
- case "maxItems" -> toType(getMaxItems(), type);
- case "minItems" -> toType(getMinItems(), type);
- case "uniqueItems" -> toType(getUniqueItems(), type);
- case "enum" -> toType(getEnum(), type);
- case "multipleOf" -> toType(getMultipleOf(), type);
- case "$ref" -> toType(getRef(), type);
+ case PROP_TYPE -> toType(getType(), type);
+ case PROP_FORMAT -> toType(getFormat(), type);
+ case PROP_ITEMS -> toType(getItems(), type);
+ case PROP_COLLECTION_FORMAT ->
toType(getCollectionFormat(), type);
+ case PROP_DEFAULT -> toType(getDefault(), type);
+ case PROP_MAXIMUM -> toType(getMaximum(), type);
+ case PROP_EXCLUSIVE_MAXIMUM ->
toType(getExclusiveMaximum(), type);
+ case PROP_MINIMUM -> toType(getMinimum(), type);
+ case PROP_EXCLUSIVE_MINIMUM ->
toType(getExclusiveMinimum(), type);
+ case PROP_MAX_LENGTH -> toType(getMaxLength(), type);
+ case PROP_MIN_LENGTH -> toType(getMinLength(), type);
+ case PROP_PATTERN -> toType(getPattern(), type);
+ case PROP_MAX_ITEMS -> toType(getMaxItems(), type);
+ case PROP_MIN_ITEMS -> toType(getMinItems(), type);
+ case PROP_UNIQUE_ITEMS -> toType(getUniqueItems(),
type);
+ case PROP_ENUM -> toType(getEnum(), type);
+ case PROP_MULTIPLE_OF -> toType(getMultipleOf(), type);
+ case PROP_REF -> toType(getRef(), type);
default -> super.get(property, type);
};
}
@@ -331,24 +351,24 @@ public class Items extends OpenApiElement {
public Set<String> keySet() {
// @formatter:off
var s = setb(String.class)
- .addIf(nn(ref), "$ref")
- .addIf(nn(collectionFormat), "collectionFormat")
- .addIf(nn(default_), "default")
- .addIf(ne(enum_), "enum")
- .addIf(nn(exclusiveMaximum), "exclusiveMaximum")
- .addIf(nn(exclusiveMinimum), "exclusiveMinimum")
- .addIf(nn(format), "format")
- .addIf(nn(items), "items")
- .addIf(nn(maxItems), "maxItems")
- .addIf(nn(maxLength), "maxLength")
- .addIf(nn(maximum), "maximum")
- .addIf(nn(minItems), "minItems")
- .addIf(nn(minLength), "minLength")
- .addIf(nn(minimum), "minimum")
- .addIf(nn(multipleOf), "multipleOf")
- .addIf(nn(pattern), "pattern")
- .addIf(nn(type), "type")
- .addIf(nn(uniqueItems), "uniqueItems")
+ .addIf(nn(ref), PROP_REF)
+ .addIf(nn(collectionFormat), PROP_COLLECTION_FORMAT)
+ .addIf(nn(default_), PROP_DEFAULT)
+ .addIf(ne(enum_), PROP_ENUM)
+ .addIf(nn(exclusiveMaximum), PROP_EXCLUSIVE_MAXIMUM)
+ .addIf(nn(exclusiveMinimum), PROP_EXCLUSIVE_MINIMUM)
+ .addIf(nn(format), PROP_FORMAT)
+ .addIf(nn(items), PROP_ITEMS)
+ .addIf(nn(maxItems), PROP_MAX_ITEMS)
+ .addIf(nn(maxLength), PROP_MAX_LENGTH)
+ .addIf(nn(maximum), PROP_MAXIMUM)
+ .addIf(nn(minItems), PROP_MIN_ITEMS)
+ .addIf(nn(minLength), PROP_MIN_LENGTH)
+ .addIf(nn(minimum), PROP_MINIMUM)
+ .addIf(nn(multipleOf), PROP_MULTIPLE_OF)
+ .addIf(nn(pattern), PROP_PATTERN)
+ .addIf(nn(type), PROP_TYPE)
+ .addIf(nn(uniqueItems), PROP_UNIQUE_ITEMS)
.build();
// @formatter:on
return new MultiSet<>(s, super.keySet());
@@ -393,24 +413,24 @@ public class Items extends OpenApiElement {
public Items set(String property, Object value) {
assertArgNotNull("property", property);
return switch (property) {
- case "$ref" -> setRef(value);
- case "collectionFormat" ->
setCollectionFormat(s(value));
- case "default" -> setDefault(value);
- case "enum" -> setEnum(value);
- case "exclusiveMaximum" ->
setExclusiveMaximum(toBoolean(value));
- case "exclusiveMinimum" ->
setExclusiveMinimum(toBoolean(value));
- case "format" -> setFormat(s(value));
- case "items" -> setItems(toType(value, Items.class));
- case "maxItems" -> setMaxItems(toInteger(value));
- case "maxLength" -> setMaxLength(toInteger(value));
- case "maximum" -> setMaximum(toNumber(value));
- case "minItems" -> setMinItems(toInteger(value));
- case "minLength" -> setMinLength(toInteger(value));
- case "minimum" -> setMinimum(toNumber(value));
- case "multipleOf" -> setMultipleOf(toNumber(value));
- case "pattern" -> setPattern(s(value));
- case "type" -> setType(s(value));
- case "uniqueItems" -> setUniqueItems(toBoolean(value));
+ case PROP_REF -> setRef(value);
+ case PROP_COLLECTION_FORMAT ->
setCollectionFormat(s(value));
+ case PROP_DEFAULT -> setDefault(value);
+ case PROP_ENUM -> setEnum(value);
+ case PROP_EXCLUSIVE_MAXIMUM ->
setExclusiveMaximum(toBoolean(value));
+ case PROP_EXCLUSIVE_MINIMUM ->
setExclusiveMinimum(toBoolean(value));
+ case PROP_FORMAT -> setFormat(s(value));
+ case PROP_ITEMS -> setItems(toType(value, Items.class));
+ case PROP_MAX_ITEMS -> setMaxItems(toInteger(value));
+ case PROP_MAX_LENGTH -> setMaxLength(toInteger(value));
+ case PROP_MAXIMUM -> setMaximum(toNumber(value));
+ case PROP_MIN_ITEMS -> setMinItems(toInteger(value));
+ case PROP_MIN_LENGTH -> setMinLength(toInteger(value));
+ case PROP_MINIMUM -> setMinimum(toNumber(value));
+ case PROP_MULTIPLE_OF -> setMultipleOf(toNumber(value));
+ case PROP_PATTERN -> setPattern(s(value));
+ case PROP_TYPE -> setType(s(value));
+ case PROP_UNIQUE_ITEMS ->
setUniqueItems(toBoolean(value));
default -> {
super.set(property, value);
yield this;
diff --git
a/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/Link.java
b/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/Link.java
index 25e1c2c614..347272d22f 100644
---
a/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/Link.java
+++
b/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/Link.java
@@ -64,6 +64,14 @@ import org.apache.juneau.commons.collections.*;
*/
public class Link extends OpenApiElement {
+ // Property name constants
+ private static final String PROP_DESCRIPTION = "description";
+ private static final String PROP_OPERATION_ID = "operationId";
+ private static final String PROP_OPERATION_REF = "operationRef";
+ private static final String PROP_PARAMETERS = "parameters";
+ private static final String PROP_REQUEST_BODY = "requestBody";
+ private static final String PROP_SERVER = "server";
+
private String operationRef;
private String operationId;
private String description;
@@ -120,12 +128,12 @@ public class Link extends OpenApiElement {
public <T> T get(String property, Class<T> type) {
assertArgNotNull("property", property);
return switch (property) {
- case "description" -> toType(getDescription(), type);
- case "operationRef" -> toType(getOperationRef(), type);
- case "operationId" -> toType(getOperationId(), type);
- case "requestBody" -> toType(getRequestBody(), type);
- case "parameters" -> toType(getParameters(), type);
- case "server" -> toType(getServer(), type);
+ case PROP_DESCRIPTION -> toType(getDescription(), type);
+ case PROP_OPERATION_REF -> toType(getOperationRef(),
type);
+ case PROP_OPERATION_ID -> toType(getOperationId(),
type);
+ case PROP_REQUEST_BODY -> toType(getRequestBody(),
type);
+ case PROP_PARAMETERS -> toType(getParameters(), type);
+ case PROP_SERVER -> toType(getServer(), type);
default -> super.get(property, type);
};
}
@@ -195,12 +203,12 @@ public class Link extends OpenApiElement {
public Set<String> keySet() {
// @formatter:off
var s = setb(String.class)
- .addIf(nn(description), "description")
- .addIf(nn(operationId), "operationId")
- .addIf(nn(operationRef), "operationRef")
- .addIf(ne(parameters), "parameters")
- .addIf(nn(requestBody), "requestBody")
- .addIf(nn(server), "server")
+ .addIf(nn(description), PROP_DESCRIPTION)
+ .addIf(nn(operationId), PROP_OPERATION_ID)
+ .addIf(nn(operationRef), PROP_OPERATION_REF)
+ .addIf(ne(parameters), PROP_PARAMETERS)
+ .addIf(nn(requestBody), PROP_REQUEST_BODY)
+ .addIf(nn(server), PROP_SERVER)
.build();
// @formatter:on
return new MultiSet<>(s, super.keySet());
@@ -210,12 +218,12 @@ public class Link extends OpenApiElement {
public Link set(String property, Object value) {
assertArgNotNull("property", property);
return switch (property) {
- case "description" -> setDescription(s(value));
- case "operationId" -> setOperationId(s(value));
- case "operationRef" -> setOperationRef(s(value));
- case "parameters" -> setParameters(toMapBuilder(value,
String.class, Object.class).sparse().build());
- case "requestBody" -> setRequestBody(value);
- case "server" -> setServer(toType(value, Server.class));
+ case PROP_DESCRIPTION -> setDescription(s(value));
+ case PROP_OPERATION_ID -> setOperationId(s(value));
+ case PROP_OPERATION_REF -> setOperationRef(s(value));
+ case PROP_PARAMETERS ->
setParameters(toMapBuilder(value, String.class, Object.class).sparse().build());
+ case PROP_REQUEST_BODY -> setRequestBody(value);
+ case PROP_SERVER -> setServer(toType(value,
Server.class));
default -> {
super.set(property, value);
yield this;
diff --git
a/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/OpenApi.java
b/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/OpenApi.java
index a3efa151f3..8644da498c 100644
---
a/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/OpenApi.java
+++
b/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/OpenApi.java
@@ -82,6 +82,16 @@ public class OpenApi extends OpenApiElement {
private static final Comparator<String> PATH_COMPARATOR = (o1, o2) ->
o1.replace('{', '@').compareTo(o2.replace('{', '@'));
+ // Property name constants
+ private static final String PROP_COMPONENTS = "components";
+ private static final String PROP_EXTERNAL_DOCS = "externalDocs";
+ private static final String PROP_INFO = "info";
+ private static final String PROP_OPENAPI = "openapi";
+ private static final String PROP_PATHS = "paths";
+ private static final String PROP_SECURITY = "security";
+ private static final String PROP_SERVERS = "servers";
+ private static final String PROP_TAGS = "tags";
+
private String openapi = "3.0.0";
private Info info;
private List<Server> servers = list();
@@ -268,14 +278,14 @@ public class OpenApi extends OpenApiElement {
public <T> T get(String property, Class<T> type) {
assertArgNotNull("property", property);
return switch (property) {
- case "openapi" -> toType(getOpenapi(), type);
- case "info" -> toType(getInfo(), type);
- case "servers" -> toType(getServers(), type);
- case "paths" -> toType(getPaths(), type);
- case "components" -> toType(getComponents(), type);
- case "security" -> toType(getSecurity(), type);
- case "tags" -> toType(getTags(), type);
- case "externalDocs" -> toType(getExternalDocs(), type);
+ case PROP_OPENAPI -> toType(getOpenapi(), type);
+ case PROP_INFO -> toType(getInfo(), type);
+ case PROP_SERVERS -> toType(getServers(), type);
+ case PROP_PATHS -> toType(getPaths(), type);
+ case PROP_COMPONENTS -> toType(getComponents(), type);
+ case PROP_SECURITY -> toType(getSecurity(), type);
+ case PROP_TAGS -> toType(getTags(), type);
+ case PROP_EXTERNAL_DOCS -> toType(getExternalDocs(),
type);
default -> super.get(property, type);
};
}
@@ -340,14 +350,14 @@ public class OpenApi extends OpenApiElement {
public Set<String> keySet() {
// @formatter:off
var s = setb(String.class)
- .addIf(nn(components), "components")
- .addIf(nn(externalDocs), "externalDocs")
- .addIf(nn(info), "info")
- .addIf(nn(openapi), "openapi")
- .addIf(nn(paths), "paths")
- .addIf(ne(security), "security")
- .addIf(ne(servers), "servers")
- .addIf(ne(tags), "tags")
+ .addIf(nn(components), PROP_COMPONENTS)
+ .addIf(nn(externalDocs), PROP_EXTERNAL_DOCS)
+ .addIf(nn(info), PROP_INFO)
+ .addIf(nn(openapi), PROP_OPENAPI)
+ .addIf(nn(paths), PROP_PATHS)
+ .addIf(ne(security), PROP_SECURITY)
+ .addIf(ne(servers), PROP_SERVERS)
+ .addIf(ne(tags), PROP_TAGS)
.build();
// @formatter:on
return new MultiSet<>(s, super.keySet());
@@ -357,14 +367,14 @@ public class OpenApi extends OpenApiElement {
public OpenApi set(String property, Object value) {
assertArgNotNull("property", property);
return switch (property) {
- case "components" -> setComponents(toType(value,
Components.class));
- case "externalDocs" -> setExternalDocs(toType(value,
ExternalDocumentation.class));
- case "info" -> setInfo(toType(value, Info.class));
- case "openapi" -> setOpenapi(s(value));
- case "paths" -> setPaths(toMapBuilder(value,
String.class, PathItem.class).sparse().build());
- case "security" ->
setSecurity(listb(SecurityRequirement.class).addAny(value).sparse().build());
- case "servers" ->
setServers(listb(Server.class).addAny(value).sparse().build());
- case "tags" ->
setTags(listb(Tag.class).addAny(value).sparse().build());
+ case PROP_COMPONENTS -> setComponents(toType(value,
Components.class));
+ case PROP_EXTERNAL_DOCS ->
setExternalDocs(toType(value, ExternalDocumentation.class));
+ case PROP_INFO -> setInfo(toType(value, Info.class));
+ case PROP_OPENAPI -> setOpenapi(s(value));
+ case PROP_PATHS -> setPaths(toMapBuilder(value,
String.class, PathItem.class).sparse().build());
+ case PROP_SECURITY ->
setSecurity(listb(SecurityRequirement.class).addAny(value).sparse().build());
+ case PROP_SERVERS ->
setServers(listb(Server.class).addAny(value).sparse().build());
+ case PROP_TAGS ->
setTags(listb(Tag.class).addAny(value).sparse().build());
default -> {
super.set(property, value);
yield this;
diff --git
a/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/Operation.java
b/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/Operation.java
index 65336a5f68..b2a607e8da 100644
---
a/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/Operation.java
+++
b/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/Operation.java
@@ -91,6 +91,20 @@ import org.apache.juneau.commons.collections.*;
*/
public class Operation extends OpenApiElement {
+ // Property name constants
+ private static final String PROP_CALLBACKS = "callbacks";
+ private static final String PROP_DEPRECATED = "deprecated";
+ private static final String PROP_DESCRIPTION = "description";
+ private static final String PROP_EXTERNAL_DOCS = "externalDocs";
+ private static final String PROP_OPERATION_ID = "operationId";
+ private static final String PROP_PARAMETERS = "parameters";
+ private static final String PROP_REQUEST_BODY = "requestBody";
+ private static final String PROP_RESPONSES = "responses";
+ private static final String PROP_SECURITY = "security";
+ private static final String PROP_SERVERS = "servers";
+ private static final String PROP_SUMMARY = "summary";
+ private static final String PROP_TAGS = "tags";
+
private List<String> tags = list();
private String summary, description, operationId;
private ExternalDocumentation externalDocs;
@@ -333,18 +347,18 @@ public class Operation extends OpenApiElement {
public <T> T get(String property, Class<T> type) {
assertArgNotNull("property", property);
return switch (property) {
- case "tags" -> toType(getTags(), type);
- case "summary" -> toType(getSummary(), type);
- case "description" -> toType(getDescription(), type);
- case "operationId" -> toType(getOperationId(), type);
- case "externalDocs" -> toType(getExternalDocs(), type);
- case "parameters" -> toType(getParameters(), type);
- case "requestBody" -> toType(getRequestBody(), type);
- case "responses" -> toType(getResponses(), type);
- case "callbacks" -> toType(getCallbacks(), type);
- case "deprecated" -> toType(getDeprecated(), type);
- case "security" -> toType(getSecurity(), type);
- case "servers" -> toType(getServers(), type);
+ case PROP_TAGS -> toType(getTags(), type);
+ case PROP_SUMMARY -> toType(getSummary(), type);
+ case PROP_DESCRIPTION -> toType(getDescription(), type);
+ case PROP_OPERATION_ID -> toType(getOperationId(),
type);
+ case PROP_EXTERNAL_DOCS -> toType(getExternalDocs(),
type);
+ case PROP_PARAMETERS -> toType(getParameters(), type);
+ case PROP_REQUEST_BODY -> toType(getRequestBody(),
type);
+ case PROP_RESPONSES -> toType(getResponses(), type);
+ case PROP_CALLBACKS -> toType(getCallbacks(), type);
+ case PROP_DEPRECATED -> toType(getDeprecated(), type);
+ case PROP_SECURITY -> toType(getSecurity(), type);
+ case PROP_SERVERS -> toType(getServers(), type);
default -> super.get(property, type);
};
}
@@ -474,18 +488,18 @@ public class Operation extends OpenApiElement {
public Set<String> keySet() {
// @formatter:off
var s = setb(String.class)
- .addIf(ne(callbacks), "callbacks")
- .addIf(nn(deprecated), "deprecated")
- .addIf(nn(description), "description")
- .addIf(nn(externalDocs), "externalDocs")
- .addIf(nn(operationId), "operationId")
- .addIf(ne(parameters), "parameters")
- .addIf(nn(requestBody), "requestBody")
- .addIf(ne(responses), "responses")
- .addIf(ne(security), "security")
- .addIf(ne(servers), "servers")
- .addIf(nn(summary), "summary")
- .addIf(ne(tags), "tags")
+ .addIf(ne(callbacks), PROP_CALLBACKS)
+ .addIf(nn(deprecated), PROP_DEPRECATED)
+ .addIf(nn(description), PROP_DESCRIPTION)
+ .addIf(nn(externalDocs), PROP_EXTERNAL_DOCS)
+ .addIf(nn(operationId), PROP_OPERATION_ID)
+ .addIf(ne(parameters), PROP_PARAMETERS)
+ .addIf(nn(requestBody), PROP_REQUEST_BODY)
+ .addIf(ne(responses), PROP_RESPONSES)
+ .addIf(ne(security), PROP_SECURITY)
+ .addIf(ne(servers), PROP_SERVERS)
+ .addIf(nn(summary), PROP_SUMMARY)
+ .addIf(ne(tags), PROP_TAGS)
.build();
// @formatter:on
return new MultiSet<>(s, super.keySet());
@@ -495,18 +509,18 @@ public class Operation extends OpenApiElement {
public Operation set(String property, Object value) {
assertArgNotNull("property", property);
return switch (property) {
- case "callbacks" -> setCallbacks(toMapBuilder(value,
String.class, Callback.class).sparse().build());
- case "deprecated" -> setDeprecated(toType(value,
Boolean.class));
- case "description" -> setDescription(s(value));
- case "externalDocs" -> setExternalDocs(toType(value,
ExternalDocumentation.class));
- case "operationId" -> setOperationId(s(value));
- case "parameters" -> setParameters(toListBuilder(value,
Parameter.class).sparse().build());
- case "requestBody" -> setRequestBody(toType(value,
RequestBodyInfo.class));
- case "responses" -> setResponses(toMapBuilder(value,
String.class, Response.class).sparse().build());
- case "security" -> setSecurity(toListBuilder(value,
SecurityRequirement.class).sparse().build());
- case "servers" -> setServers(toListBuilder(value,
Server.class).sparse().build());
- case "summary" -> setSummary(s(value));
- case "tags" -> setTags(toListBuilder(value,
String.class).sparse().build());
+ case PROP_CALLBACKS -> setCallbacks(toMapBuilder(value,
String.class, Callback.class).sparse().build());
+ case PROP_DEPRECATED -> setDeprecated(toType(value,
Boolean.class));
+ case PROP_DESCRIPTION -> setDescription(s(value));
+ case PROP_EXTERNAL_DOCS ->
setExternalDocs(toType(value, ExternalDocumentation.class));
+ case PROP_OPERATION_ID -> setOperationId(s(value));
+ case PROP_PARAMETERS ->
setParameters(toListBuilder(value, Parameter.class).sparse().build());
+ case PROP_REQUEST_BODY -> setRequestBody(toType(value,
RequestBodyInfo.class));
+ case PROP_RESPONSES -> setResponses(toMapBuilder(value,
String.class, Response.class).sparse().build());
+ case PROP_SECURITY -> setSecurity(toListBuilder(value,
SecurityRequirement.class).sparse().build());
+ case PROP_SERVERS -> setServers(toListBuilder(value,
Server.class).sparse().build());
+ case PROP_SUMMARY -> setSummary(s(value));
+ case PROP_TAGS -> setTags(toListBuilder(value,
String.class).sparse().build());
default -> {
super.set(property, value);
yield this;
diff --git
a/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/Parameter.java
b/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/Parameter.java
index f932b39284..99c0ccf2db 100644
---
a/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/Parameter.java
+++
b/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/Parameter.java
@@ -83,6 +83,20 @@ public class Parameter extends OpenApiElement {
private static final String[] VALID_IN = { "query", "header", "path",
"cookie" };
private static final String[] VALID_STYLES = { "matrix", "label",
"form", "simple", "spaceDelimited", "pipeDelimited", "deepObject" };
+ // Property name constants
+ private static final String PROP_ALLOW_EMPTY_VALUE = "allowEmptyValue";
+ private static final String PROP_ALLOW_RESERVED = "allowReserved";
+ private static final String PROP_DEPRECATED = "deprecated";
+ private static final String PROP_DESCRIPTION = "description";
+ private static final String PROP_EXAMPLE = "example";
+ private static final String PROP_EXAMPLES = "examples";
+ private static final String PROP_EXPLODE = "explode";
+ private static final String PROP_IN = "in";
+ private static final String PROP_NAME = "name";
+ private static final String PROP_REQUIRED = "required";
+ private static final String PROP_SCHEMA = "schema";
+ private static final String PROP_STYLE = "style";
+
private String name, in, description, style;
private Boolean required, deprecated, allowEmptyValue, explode,
allowReserved;
private SchemaInfo schema;
@@ -128,18 +142,18 @@ public class Parameter extends OpenApiElement {
public <T> T get(String property, Class<T> type) {
assertArgNotNull("property", property);
return switch (property) {
- case "name" -> toType(getName(), type);
- case "in" -> toType(getIn(), type);
- case "description" -> toType(getDescription(), type);
- case "required" -> toType(getRequired(), type);
- case "deprecated" -> toType(getDeprecated(), type);
- case "allowEmptyValue" -> toType(getAllowEmptyValue(),
type);
- case "style" -> toType(getStyle(), type);
- case "explode" -> toType(getExplode(), type);
- case "allowReserved" -> toType(getAllowReserved(),
type);
- case "schema" -> toType(getSchema(), type);
- case "example" -> toType(getExample(), type);
- case "examples" -> toType(getExamples(), type);
+ case PROP_NAME -> toType(getName(), type);
+ case PROP_IN -> toType(getIn(), type);
+ case PROP_DESCRIPTION -> toType(getDescription(), type);
+ case PROP_REQUIRED -> toType(getRequired(), type);
+ case PROP_DEPRECATED -> toType(getDeprecated(), type);
+ case PROP_ALLOW_EMPTY_VALUE ->
toType(getAllowEmptyValue(), type);
+ case PROP_STYLE -> toType(getStyle(), type);
+ case PROP_EXPLODE -> toType(getExplode(), type);
+ case PROP_ALLOW_RESERVED -> toType(getAllowReserved(),
type);
+ case PROP_SCHEMA -> toType(getSchema(), type);
+ case PROP_EXAMPLE -> toType(getExample(), type);
+ case PROP_EXAMPLES -> toType(getExamples(), type);
default -> super.get(property, type);
};
}
@@ -232,18 +246,18 @@ public class Parameter extends OpenApiElement {
public Set<String> keySet() {
// @formatter:off
var s = setb(String.class)
- .addIf(nn(allowEmptyValue), "allowEmptyValue")
- .addIf(nn(allowReserved), "allowReserved")
- .addIf(nn(deprecated), "deprecated")
- .addIf(nn(description), "description")
- .addIf(nn(example), "example")
- .addIf(nn(examples), "examples")
- .addIf(nn(explode), "explode")
- .addIf(nn(in), "in")
- .addIf(nn(name), "name")
- .addIf(nn(required), "required")
- .addIf(nn(schema), "schema")
- .addIf(nn(style), "style")
+ .addIf(nn(allowEmptyValue), PROP_ALLOW_EMPTY_VALUE)
+ .addIf(nn(allowReserved), PROP_ALLOW_RESERVED)
+ .addIf(nn(deprecated), PROP_DEPRECATED)
+ .addIf(nn(description), PROP_DESCRIPTION)
+ .addIf(nn(example), PROP_EXAMPLE)
+ .addIf(nn(examples), PROP_EXAMPLES)
+ .addIf(nn(explode), PROP_EXPLODE)
+ .addIf(nn(in), PROP_IN)
+ .addIf(nn(name), PROP_NAME)
+ .addIf(nn(required), PROP_REQUIRED)
+ .addIf(nn(schema), PROP_SCHEMA)
+ .addIf(nn(style), PROP_STYLE)
.build();
// @formatter:on
return new MultiSet<>(s, super.keySet());
@@ -253,18 +267,18 @@ public class Parameter extends OpenApiElement {
public Parameter set(String property, Object value) {
assertArgNotNull("property", property);
return switch (property) {
- case "allowEmptyValue" ->
setAllowEmptyValue(toType(value, Boolean.class));
- case "allowReserved" -> setAllowReserved(toType(value,
Boolean.class));
- case "description" -> setDescription(s(value));
- case "deprecated" -> setDeprecated(toType(value,
Boolean.class));
- case "example" -> setExample(value);
- case "examples" -> setExamples(toMapBuilder(value,
String.class, Example.class).sparse().build());
- case "explode" -> setExplode(toType(value,
Boolean.class));
- case "in" -> setIn(s(value));
- case "name" -> setName(s(value));
- case "required" -> setRequired(toType(value,
Boolean.class));
- case "schema" -> setSchema(toType(value,
SchemaInfo.class));
- case "style" -> setStyle(s(value));
+ case PROP_ALLOW_EMPTY_VALUE ->
setAllowEmptyValue(toType(value, Boolean.class));
+ case PROP_ALLOW_RESERVED ->
setAllowReserved(toType(value, Boolean.class));
+ case PROP_DESCRIPTION -> setDescription(s(value));
+ case PROP_DEPRECATED -> setDeprecated(toType(value,
Boolean.class));
+ case PROP_EXAMPLE -> setExample(value);
+ case PROP_EXAMPLES -> setExamples(toMapBuilder(value,
String.class, Example.class).sparse().build());
+ case PROP_EXPLODE -> setExplode(toType(value,
Boolean.class));
+ case PROP_IN -> setIn(s(value));
+ case PROP_NAME -> setName(s(value));
+ case PROP_REQUIRED -> setRequired(toType(value,
Boolean.class));
+ case PROP_SCHEMA -> setSchema(toType(value,
SchemaInfo.class));
+ case PROP_STYLE -> setStyle(s(value));
default -> {
super.set(property, value);
yield this;
diff --git
a/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/PathItem.java
b/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/PathItem.java
index c6f97e0465..b408c5fa25 100644
---
a/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/PathItem.java
+++
b/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/PathItem.java
@@ -82,6 +82,20 @@ import org.apache.juneau.commons.collections.*;
*/
public class PathItem extends OpenApiElement {
+ // Property name constants
+ private static final String PROP_DELETE = "delete";
+ private static final String PROP_DESCRIPTION = "description";
+ private static final String PROP_GET = "get";
+ private static final String PROP_HEAD = "head";
+ private static final String PROP_OPTIONS = "options";
+ private static final String PROP_PARAMETERS = "parameters";
+ private static final String PROP_PATCH = "patch";
+ private static final String PROP_POST = "post";
+ private static final String PROP_PUT = "put";
+ private static final String PROP_SERVERS = "servers";
+ private static final String PROP_SUMMARY = "summary";
+ private static final String PROP_TRACE = "trace";
+
private String summary, description;
private Operation get, put, post, delete, options, head, patch, trace;
private List<Server> servers;
@@ -126,18 +140,18 @@ public class PathItem extends OpenApiElement {
public <T> T get(String property, Class<T> type) {
assertArgNotNull("property", property);
return switch (property) {
- case "summary" -> toType(getSummary(), type);
- case "description" -> toType(getDescription(), type);
- case "get" -> toType(getGet(), type);
- case "put" -> toType(getPut(), type);
- case "post" -> toType(getPost(), type);
- case "delete" -> toType(getDelete(), type);
- case "options" -> toType(getOptions(), type);
- case "head" -> toType(getHead(), type);
- case "patch" -> toType(getPatch(), type);
- case "trace" -> toType(getTrace(), type);
- case "servers" -> toType(getServers(), type);
- case "parameters" -> toType(getParameters(), type);
+ case PROP_SUMMARY -> toType(getSummary(), type);
+ case PROP_DESCRIPTION -> toType(getDescription(), type);
+ case PROP_GET -> toType(getGet(), type);
+ case PROP_PUT -> toType(getPut(), type);
+ case PROP_POST -> toType(getPost(), type);
+ case PROP_DELETE -> toType(getDelete(), type);
+ case PROP_OPTIONS -> toType(getOptions(), type);
+ case PROP_HEAD -> toType(getHead(), type);
+ case PROP_PATCH -> toType(getPatch(), type);
+ case PROP_TRACE -> toType(getTrace(), type);
+ case PROP_SERVERS -> toType(getServers(), type);
+ case PROP_PARAMETERS -> toType(getParameters(), type);
default -> super.get(property, type);
};
}
@@ -230,18 +244,18 @@ public class PathItem extends OpenApiElement {
public Set<String> keySet() {
// @formatter:off
var s = setb(String.class)
- .addIf(nn(delete), "delete")
- .addIf(nn(description), "description")
- .addIf(nn(get), "get")
- .addIf(nn(head), "head")
- .addIf(nn(options), "options")
- .addIf(nn(parameters), "parameters")
- .addIf(nn(patch), "patch")
- .addIf(nn(post), "post")
- .addIf(nn(put), "put")
- .addIf(nn(servers), "servers")
- .addIf(nn(summary), "summary")
- .addIf(nn(trace), "trace")
+ .addIf(nn(delete), PROP_DELETE)
+ .addIf(nn(description), PROP_DESCRIPTION)
+ .addIf(nn(get), PROP_GET)
+ .addIf(nn(head), PROP_HEAD)
+ .addIf(nn(options), PROP_OPTIONS)
+ .addIf(nn(parameters), PROP_PARAMETERS)
+ .addIf(nn(patch), PROP_PATCH)
+ .addIf(nn(post), PROP_POST)
+ .addIf(nn(put), PROP_PUT)
+ .addIf(nn(servers), PROP_SERVERS)
+ .addIf(nn(summary), PROP_SUMMARY)
+ .addIf(nn(trace), PROP_TRACE)
.build();
// @formatter:on
return new MultiSet<>(s, super.keySet());
@@ -251,18 +265,18 @@ public class PathItem extends OpenApiElement {
public PathItem set(String property, Object value) {
assertArgNotNull("property", property);
return switch (property) {
- case "delete" -> setDelete(toType(value,
Operation.class));
- case "description" -> setDescription(s(value));
- case "get" -> setGet(toType(value, Operation.class));
- case "head" -> setHead(toType(value, Operation.class));
- case "options" -> setOptions(toType(value,
Operation.class));
- case "patch" -> setPatch(toType(value,
Operation.class));
- case "parameters" ->
setParameters(listb(Parameter.class).addAny(value).sparse().build());
- case "post" -> setPost(toType(value, Operation.class));
- case "put" -> setPut(toType(value, Operation.class));
- case "servers" ->
setServers(listb(Server.class).addAny(value).sparse().build());
- case "summary" -> setSummary(s(value));
- case "trace" -> setTrace(toType(value,
Operation.class));
+ case PROP_DELETE -> setDelete(toType(value,
Operation.class));
+ case PROP_DESCRIPTION -> setDescription(s(value));
+ case PROP_GET -> setGet(toType(value, Operation.class));
+ case PROP_HEAD -> setHead(toType(value,
Operation.class));
+ case PROP_OPTIONS -> setOptions(toType(value,
Operation.class));
+ case PROP_PATCH -> setPatch(toType(value,
Operation.class));
+ case PROP_PARAMETERS ->
setParameters(listb(Parameter.class).addAny(value).sparse().build());
+ case PROP_POST -> setPost(toType(value,
Operation.class));
+ case PROP_PUT -> setPut(toType(value, Operation.class));
+ case PROP_SERVERS ->
setServers(listb(Server.class).addAny(value).sparse().build());
+ case PROP_SUMMARY -> setSummary(s(value));
+ case PROP_TRACE -> setTrace(toType(value,
Operation.class));
default -> {
super.set(property, value);
yield this;
diff --git
a/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/RequestBodyInfo.java
b/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/RequestBodyInfo.java
index c1c908b25c..af795da448 100644
---
a/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/RequestBodyInfo.java
+++
b/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/RequestBodyInfo.java
@@ -67,6 +67,11 @@ import org.apache.juneau.commons.collections.*;
*/
public class RequestBodyInfo extends OpenApiElement {
+ // Property name constants
+ private static final String PROP_CONTENT = "content";
+ private static final String PROP_DESCRIPTION = "description";
+ private static final String PROP_REQUIRED = "required";
+
private String description;
private Map<String,MediaType> content = map();
private Boolean required;
@@ -120,9 +125,9 @@ public class RequestBodyInfo extends OpenApiElement {
public <T> T get(String property, Class<T> type) {
assertArgNotNull("property", property);
return switch (property) {
- case "description" -> toType(getDescription(), type);
- case "content" -> toType(getContent(), type);
- case "required" -> toType(getRequired(), type);
+ case PROP_DESCRIPTION -> toType(getDescription(), type);
+ case PROP_CONTENT -> toType(getContent(), type);
+ case PROP_REQUIRED -> toType(getRequired(), type);
default -> super.get(property, type);
};
}
@@ -158,9 +163,9 @@ public class RequestBodyInfo extends OpenApiElement {
public Set<String> keySet() {
// @formatter:off
var s = setb(String.class)
- .addIf(ne(content), "content")
- .addIf(nn(description), "description")
- .addIf(nn(required), "required")
+ .addIf(ne(content), PROP_CONTENT)
+ .addIf(nn(description), PROP_DESCRIPTION)
+ .addIf(nn(required), PROP_REQUIRED)
.build();
// @formatter:on
return new MultiSet<>(s, super.keySet());
@@ -170,9 +175,9 @@ public class RequestBodyInfo extends OpenApiElement {
public RequestBodyInfo set(String property, Object value) {
assertArgNotNull("property", property);
return switch (property) {
- case "content" -> setContent(toMapBuilder(value,
String.class, MediaType.class).sparse().build());
- case "description" -> setDescription(s(value));
- case "required" -> setRequired(toBoolean(value));
+ case PROP_CONTENT -> setContent(toMapBuilder(value,
String.class, MediaType.class).sparse().build());
+ case PROP_DESCRIPTION -> setDescription(s(value));
+ case PROP_REQUIRED -> setRequired(toBoolean(value));
default -> {
super.set(property, value);
yield this;
diff --git
a/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/SecuritySchemeInfo.java
b/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/SecuritySchemeInfo.java
index b0f0016ad2..e9e9bd857c 100644
---
a/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/SecuritySchemeInfo.java
+++
b/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/SecuritySchemeInfo.java
@@ -90,6 +90,16 @@ public class SecuritySchemeInfo extends OpenApiElement {
private static final String[] VALID_IN = { "query", "header", "cookie"
};
private static final String[] VALID_TYPES = { "apiKey", "http",
"oauth2", "openIdConnect" };
+ // Property name constants
+ private static final String PROP_BEARER_FORMAT = "bearerFormat";
+ private static final String PROP_DESCRIPTION = "description";
+ private static final String PROP_FLOWS = "flows";
+ private static final String PROP_IN = "in";
+ private static final String PROP_NAME = "name";
+ private static final String PROP_OPEN_ID_CONNECT_URL =
"openIdConnectUrl";
+ private static final String PROP_SCHEME = "scheme";
+ private static final String PROP_TYPE = "type";
+
private String type, description, name, in, scheme, bearerFormat,
openIdConnectUrl;
private OAuthFlow flows;
@@ -130,14 +140,14 @@ public class SecuritySchemeInfo extends OpenApiElement {
public <T> T get(String property, Class<T> type) {
assertArgNotNull("property", property);
return switch (property) {
- case "name" -> toType(getName(), type);
- case "in" -> toType(getIn(), type);
- case "description" -> toType(getDescription(), type);
- case "scheme" -> toType(getScheme(), type);
- case "flows" -> toType(getFlows(), type);
- case "bearerFormat" -> toType(getBearerFormat(), type);
- case "openIdConnectUrl" ->
toType(getOpenIdConnectUrl(), type);
- case "type" -> toType(getType(), type);
+ case PROP_NAME -> toType(getName(), type);
+ case PROP_IN -> toType(getIn(), type);
+ case PROP_DESCRIPTION -> toType(getDescription(), type);
+ case PROP_SCHEME -> toType(getScheme(), type);
+ case PROP_FLOWS -> toType(getFlows(), type);
+ case PROP_BEARER_FORMAT -> toType(getBearerFormat(),
type);
+ case PROP_OPEN_ID_CONNECT_URL ->
toType(getOpenIdConnectUrl(), type);
+ case PROP_TYPE -> toType(getType(), type);
default -> super.get(property, type);
};
}
@@ -238,14 +248,14 @@ public class SecuritySchemeInfo extends OpenApiElement {
public Set<String> keySet() {
// @formatter:off
var s = setb(String.class)
- .addIf(nn(bearerFormat), "bearerFormat")
- .addIf(nn(description), "description")
- .addIf(nn(flows), "flows")
- .addIf(nn(in), "in")
- .addIf(nn(name), "name")
- .addIf(nn(openIdConnectUrl), "openIdConnectUrl")
- .addIf(nn(scheme), "scheme")
- .addIf(nn(type), "type")
+ .addIf(nn(bearerFormat), PROP_BEARER_FORMAT)
+ .addIf(nn(description), PROP_DESCRIPTION)
+ .addIf(nn(flows), PROP_FLOWS)
+ .addIf(nn(in), PROP_IN)
+ .addIf(nn(name), PROP_NAME)
+ .addIf(nn(openIdConnectUrl), PROP_OPEN_ID_CONNECT_URL)
+ .addIf(nn(scheme), PROP_SCHEME)
+ .addIf(nn(type), PROP_TYPE)
.build();
// @formatter:on
return new MultiSet<>(s, super.keySet());
@@ -255,14 +265,14 @@ public class SecuritySchemeInfo extends OpenApiElement {
public SecuritySchemeInfo set(String property, Object value) {
assertArgNotNull("property", property);
return switch (property) {
- case "bearerFormat" -> setBearerFormat(s(value));
- case "description" -> setDescription(s(value));
- case "flows" -> setFlows(toType(value,
OAuthFlow.class));
- case "in" -> setIn(s(value));
- case "name" -> setName(s(value));
- case "openIdConnectUrl" ->
setOpenIdConnectUrl(s(value));
- case "scheme" -> setScheme(s(value));
- case "type" -> setType(s(value));
+ case PROP_BEARER_FORMAT -> setBearerFormat(s(value));
+ case PROP_DESCRIPTION -> setDescription(s(value));
+ case PROP_FLOWS -> setFlows(toType(value,
OAuthFlow.class));
+ case PROP_IN -> setIn(s(value));
+ case PROP_NAME -> setName(s(value));
+ case PROP_OPEN_ID_CONNECT_URL ->
setOpenIdConnectUrl(s(value));
+ case PROP_SCHEME -> setScheme(s(value));
+ case PROP_TYPE -> setType(s(value));
default -> {
super.set(property, value);
yield this;
diff --git
a/juneau-bean/juneau-bean-swagger-v2/src/main/java/org/apache/juneau/bean/swagger/Operation.java
b/juneau-bean/juneau-bean-swagger-v2/src/main/java/org/apache/juneau/bean/swagger/Operation.java
index 0e6f772871..5a835916e8 100644
---
a/juneau-bean/juneau-bean-swagger-v2/src/main/java/org/apache/juneau/bean/swagger/Operation.java
+++
b/juneau-bean/juneau-bean-swagger-v2/src/main/java/org/apache/juneau/bean/swagger/Operation.java
@@ -160,6 +160,20 @@ public class Operation extends SwaggerElement {
private interface MapStringList extends Map<String,List<String>> {}
+ // Property name constants
+ private static final String PROP_CONSUMES = "consumes";
+ private static final String PROP_DEPRECATED = "deprecated";
+ private static final String PROP_DESCRIPTION = "description";
+ private static final String PROP_EXTERNAL_DOCS = "externalDocs";
+ private static final String PROP_OPERATION_ID = "operationId";
+ private static final String PROP_PARAMETERS = "parameters";
+ private static final String PROP_PRODUCES = "produces";
+ private static final String PROP_RESPONSES = "responses";
+ private static final String PROP_SCHEMES = "schemes";
+ private static final String PROP_SECURITY = "security";
+ private static final String PROP_SUMMARY = "summary";
+ private static final String PROP_TAGS = "tags";
+
private String summary, description, operationId;
private Boolean deprecated;
private ExternalDocumentation externalDocs;
@@ -451,18 +465,18 @@ public class Operation extends SwaggerElement {
public <T> T get(String property, Class<T> type) {
assertArgNotNull("property", property);
return switch (property) {
- case "consumes" -> toType(getConsumes(), type);
- case "deprecated" -> toType(getDeprecated(), type);
- case "description" -> toType(getDescription(), type);
- case "externalDocs" -> toType(getExternalDocs(), type);
- case "operationId" -> toType(getOperationId(), type);
- case "parameters" -> toType(getParameters(), type);
- case "produces" -> toType(getProduces(), type);
- case "responses" -> toType(getResponses(), type);
- case "schemes" -> toType(getSchemes(), type);
- case "security" -> toType(getSecurity(), type);
- case "summary" -> toType(getSummary(), type);
- case "tags" -> toType(getTags(), type);
+ case PROP_CONSUMES -> toType(getConsumes(), type);
+ case PROP_DEPRECATED -> toType(getDeprecated(), type);
+ case PROP_DESCRIPTION -> toType(getDescription(), type);
+ case PROP_EXTERNAL_DOCS -> toType(getExternalDocs(),
type);
+ case PROP_OPERATION_ID -> toType(getOperationId(),
type);
+ case PROP_PARAMETERS -> toType(getParameters(), type);
+ case PROP_PRODUCES -> toType(getProduces(), type);
+ case PROP_RESPONSES -> toType(getResponses(), type);
+ case PROP_SCHEMES -> toType(getSchemes(), type);
+ case PROP_SECURITY -> toType(getSecurity(), type);
+ case PROP_SUMMARY -> toType(getSummary(), type);
+ case PROP_TAGS -> toType(getTags(), type);
default -> super.get(property, type);
};
}
@@ -654,18 +668,18 @@ public class Operation extends SwaggerElement {
public Set<String> keySet() {
// @formatter:off
var s = setb(String.class)
- .addIf(ne(consumes), "consumes")
- .addIf(nn(deprecated), "deprecated")
- .addIf(nn(description), "description")
- .addIf(nn(externalDocs), "externalDocs")
- .addIf(nn(operationId), "operationId")
- .addIf(ne(parameters), "parameters")
- .addIf(ne(produces), "produces")
- .addIf(ne(responses), "responses")
- .addIf(ne(schemes), "schemes")
- .addIf(ne(security), "security")
- .addIf(nn(summary), "summary")
- .addIf(ne(tags), "tags")
+ .addIf(ne(consumes), PROP_CONSUMES)
+ .addIf(nn(deprecated), PROP_DEPRECATED)
+ .addIf(nn(description), PROP_DESCRIPTION)
+ .addIf(nn(externalDocs), PROP_EXTERNAL_DOCS)
+ .addIf(nn(operationId), PROP_OPERATION_ID)
+ .addIf(ne(parameters), PROP_PARAMETERS)
+ .addIf(ne(produces), PROP_PRODUCES)
+ .addIf(ne(responses), PROP_RESPONSES)
+ .addIf(ne(schemes), PROP_SCHEMES)
+ .addIf(ne(security), PROP_SECURITY)
+ .addIf(nn(summary), PROP_SUMMARY)
+ .addIf(ne(tags), PROP_TAGS)
.build();
// @formatter:on
return new MultiSet<>(s, super.keySet());
@@ -676,18 +690,18 @@ public class Operation extends SwaggerElement {
public Operation set(String property, Object value) {
assertArgNotNull("property", property);
return switch (property) {
- case "consumes" -> setConsumes(toListBuilder(value,
MediaType.class).sparse().build());
- case "deprecated" -> setDeprecated(toBoolean(value));
- case "description" -> setDescription(s(value));
- case "externalDocs" -> setExternalDocs(toType(value,
ExternalDocumentation.class));
- case "operationId" -> setOperationId(s(value));
- case "parameters" -> setParameters(toListBuilder(value,
ParameterInfo.class).sparse().build());
- case "produces" -> setProduces(toListBuilder(value,
MediaType.class).sparse().build());
- case "responses" -> setResponses(toMapBuilder(value,
String.class, ResponseInfo.class).sparse().build());
- case "schemes" -> setSchemes(toListBuilder(value,
String.class).sparse().addAny(value).build());
- case "security" ->
setSecurity((List)toListBuilder(value, MapStringList.class).sparse().build());
- case "summary" -> setSummary(s(value));
- case "tags" -> setTags(toListBuilder(value,
String.class).sparse().build());
+ case PROP_CONSUMES -> setConsumes(toListBuilder(value,
MediaType.class).sparse().build());
+ case PROP_DEPRECATED -> setDeprecated(toBoolean(value));
+ case PROP_DESCRIPTION -> setDescription(s(value));
+ case PROP_EXTERNAL_DOCS ->
setExternalDocs(toType(value, ExternalDocumentation.class));
+ case PROP_OPERATION_ID -> setOperationId(s(value));
+ case PROP_PARAMETERS ->
setParameters(toListBuilder(value, ParameterInfo.class).sparse().build());
+ case PROP_PRODUCES -> setProduces(toListBuilder(value,
MediaType.class).sparse().build());
+ case PROP_RESPONSES -> setResponses(toMapBuilder(value,
String.class, ResponseInfo.class).sparse().build());
+ case PROP_SCHEMES -> setSchemes(toListBuilder(value,
String.class).sparse().addAny(value).build());
+ case PROP_SECURITY ->
setSecurity((List)toListBuilder(value, MapStringList.class).sparse().build());
+ case PROP_SUMMARY -> setSummary(s(value));
+ case PROP_TAGS -> setTags(toListBuilder(value,
String.class).sparse().build());
default -> {
super.set(property, value);
yield this;
diff --git
a/juneau-bean/juneau-bean-swagger-v2/src/main/java/org/apache/juneau/bean/swagger/Swagger.java
b/juneau-bean/juneau-bean-swagger-v2/src/main/java/org/apache/juneau/bean/swagger/Swagger.java
index 823c484e9e..2cbe145686 100644
---
a/juneau-bean/juneau-bean-swagger-v2/src/main/java/org/apache/juneau/bean/swagger/Swagger.java
+++
b/juneau-bean/juneau-bean-swagger-v2/src/main/java/org/apache/juneau/bean/swagger/Swagger.java
@@ -93,6 +93,24 @@ public class Swagger extends SwaggerElement {
public static final Swagger NULL = new Swagger();
private static final Comparator<String> PATH_COMPARATOR = (o1, o2) ->
o1.replace('{', '@').compareTo(o2.replace('{', '@'));
+
+ // Property name constants
+ private static final String PROP_BASE_PATH = "basePath";
+ private static final String PROP_CONSUMES = "consumes";
+ private static final String PROP_DEFINITIONS = "definitions";
+ private static final String PROP_EXTERNAL_DOCS = "externalDocs";
+ private static final String PROP_HOST = "host";
+ private static final String PROP_INFO = "info";
+ private static final String PROP_PARAMETERS = "parameters";
+ private static final String PROP_PATHS = "paths";
+ private static final String PROP_PRODUCES = "produces";
+ private static final String PROP_RESPONSES = "responses";
+ private static final String PROP_SCHEMES = "schemes";
+ private static final String PROP_SECURITY = "security";
+ private static final String PROP_SECURITY_DEFINITIONS =
"securityDefinitions";
+ private static final String PROP_SWAGGER = "swagger";
+ private static final String PROP_TAGS = "tags";
+
private String swagger = "2.0", // NOSONAR - Intentional naming.
host, basePath;
private Info info;
@@ -495,21 +513,21 @@ public class Swagger extends SwaggerElement {
public <T> T get(String property, Class<T> type) {
assertArgNotNull("property", property);
return switch (property) {
- case "basePath" -> toType(getBasePath(), type);
- case "consumes" -> toType(getConsumes(), type);
- case "definitions" -> toType(getDefinitions(), type);
- case "externalDocs" -> toType(getExternalDocs(), type);
- case "host" -> toType(getHost(), type);
- case "info" -> toType(getInfo(), type);
- case "parameters" -> toType(getParameters(), type);
- case "paths" -> toType(getPaths(), type);
- case "produces" -> toType(getProduces(), type);
- case "responses" -> toType(getResponses(), type);
- case "schemes" -> toType(getSchemes(), type);
- case "security" -> toType(getSecurity(), type);
- case "securityDefinitions" ->
toType(getSecurityDefinitions(), type);
- case "swagger" -> toType(getSwagger(), type);
- case "tags" -> toType(getTags(), type);
+ case PROP_BASE_PATH -> toType(getBasePath(), type);
+ case PROP_CONSUMES -> toType(getConsumes(), type);
+ case PROP_DEFINITIONS -> toType(getDefinitions(), type);
+ case PROP_EXTERNAL_DOCS -> toType(getExternalDocs(),
type);
+ case PROP_HOST -> toType(getHost(), type);
+ case PROP_INFO -> toType(getInfo(), type);
+ case PROP_PARAMETERS -> toType(getParameters(), type);
+ case PROP_PATHS -> toType(getPaths(), type);
+ case PROP_PRODUCES -> toType(getProduces(), type);
+ case PROP_RESPONSES -> toType(getResponses(), type);
+ case PROP_SCHEMES -> toType(getSchemes(), type);
+ case PROP_SECURITY -> toType(getSecurity(), type);
+ case PROP_SECURITY_DEFINITIONS ->
toType(getSecurityDefinitions(), type);
+ case PROP_SWAGGER -> toType(getSwagger(), type);
+ case PROP_TAGS -> toType(getTags(), type);
default -> super.get(property, type);
};
}
@@ -735,21 +753,21 @@ public class Swagger extends SwaggerElement {
public Set<String> keySet() {
// @formatter:off
var s = setb(String.class)
- .addIf(nn(basePath), "basePath")
- .addIf(ne(consumes), "consumes")
- .addIf(ne(definitions), "definitions")
- .addIf(nn(externalDocs), "externalDocs")
- .addIf(nn(host), "host")
- .addIf(nn(info), "info")
- .addIf(ne(parameters), "parameters")
- .addIf(ne(paths), "paths")
- .addIf(ne(produces), "produces")
- .addIf(ne(responses), "responses")
- .addIf(ne(schemes), "schemes")
- .addIf(ne(security), "security")
- .addIf(ne(securityDefinitions), "securityDefinitions")
- .addIf(nn(swagger), "swagger")
- .addIf(ne(tags), "tags")
+ .addIf(nn(basePath), PROP_BASE_PATH)
+ .addIf(ne(consumes), PROP_CONSUMES)
+ .addIf(ne(definitions), PROP_DEFINITIONS)
+ .addIf(nn(externalDocs), PROP_EXTERNAL_DOCS)
+ .addIf(nn(host), PROP_HOST)
+ .addIf(nn(info), PROP_INFO)
+ .addIf(ne(parameters), PROP_PARAMETERS)
+ .addIf(ne(paths), PROP_PATHS)
+ .addIf(ne(produces), PROP_PRODUCES)
+ .addIf(ne(responses), PROP_RESPONSES)
+ .addIf(ne(schemes), PROP_SCHEMES)
+ .addIf(ne(security), PROP_SECURITY)
+ .addIf(ne(securityDefinitions),
PROP_SECURITY_DEFINITIONS)
+ .addIf(nn(swagger), PROP_SWAGGER)
+ .addIf(ne(tags), PROP_TAGS)
.build();
// @formatter:on
return new MultiSet<>(s, super.keySet());
@@ -760,21 +778,21 @@ public class Swagger extends SwaggerElement {
public Swagger set(String property, Object value) {
assertArgNotNull("property", property);
return switch (property) {
- case "basePath" -> setBasePath(s(value));
- case "consumes" -> setConsumes(toListBuilder(value,
MediaType.class).sparse().build());
- case "definitions" ->
setDefinitions(toMapBuilder(value, String.class,
JsonMap.class).sparse().build());
- case "externalDocs" -> setExternalDocs(toType(value,
ExternalDocumentation.class));
- case "host" -> setHost(s(value));
- case "info" -> setInfo(toType(value, Info.class));
- case "parameters" -> setParameters(toMapBuilder(value,
String.class, ParameterInfo.class).sparse().build());
- case "paths" -> setPaths(toMapBuilder(value,
String.class, OperationMap.class).sparse().build());
- case "produces" -> setProduces(toListBuilder(value,
MediaType.class).sparse().build());
- case "responses" -> setResponses(toMapBuilder(value,
String.class, ResponseInfo.class).sparse().build());
- case "schemes" -> setSchemes(toListBuilder(value,
String.class).sparse().build());
- case "security" ->
setSecurity((List)toListBuilder(value,
MapOfStringLists.class).sparse().build());
- case "securityDefinitions" ->
setSecurityDefinitions(toMapBuilder(value, String.class,
SecurityScheme.class).sparse().build());
- case "swagger" -> setSwagger(s(value));
- case "tags" -> setTags(toListBuilder(value,
Tag.class).sparse().build());
+ case PROP_BASE_PATH -> setBasePath(s(value));
+ case PROP_CONSUMES -> setConsumes(toListBuilder(value,
MediaType.class).sparse().build());
+ case PROP_DEFINITIONS ->
setDefinitions(toMapBuilder(value, String.class,
JsonMap.class).sparse().build());
+ case PROP_EXTERNAL_DOCS ->
setExternalDocs(toType(value, ExternalDocumentation.class));
+ case PROP_HOST -> setHost(s(value));
+ case PROP_INFO -> setInfo(toType(value, Info.class));
+ case PROP_PARAMETERS ->
setParameters(toMapBuilder(value, String.class,
ParameterInfo.class).sparse().build());
+ case PROP_PATHS -> setPaths(toMapBuilder(value,
String.class, OperationMap.class).sparse().build());
+ case PROP_PRODUCES -> setProduces(toListBuilder(value,
MediaType.class).sparse().build());
+ case PROP_RESPONSES -> setResponses(toMapBuilder(value,
String.class, ResponseInfo.class).sparse().build());
+ case PROP_SCHEMES -> setSchemes(toListBuilder(value,
String.class).sparse().build());
+ case PROP_SECURITY ->
setSecurity((List)toListBuilder(value,
MapOfStringLists.class).sparse().build());
+ case PROP_SECURITY_DEFINITIONS ->
setSecurityDefinitions(toMapBuilder(value, String.class,
SecurityScheme.class).sparse().build());
+ case PROP_SWAGGER -> setSwagger(s(value));
+ case PROP_TAGS -> setTags(toListBuilder(value,
Tag.class).sparse().build());
default -> {
super.set(property, value);
yield this;
diff --git a/scripts/README_SONARQUBE.md b/scripts/README_SONARQUBE.md
new file mode 100644
index 0000000000..3752dc6843
--- /dev/null
+++ b/scripts/README_SONARQUBE.md
@@ -0,0 +1,217 @@
+# SonarQube Issues Management Tools
+
+This directory contains tools for categorizing and managing SonarQube issues
in the Apache Juneau project.
+
+## Overview
+
+The Apache Juneau project has **3,116 SonarQube issues** that have been
categorized into **30 categories** for systematic fixing.
+
+## Quick Start
+
+### 1. View Category Summary
+
+```bash
+cd /Users/james.bognar/git/apache/juneau/master
+cat SONARQUBE_ISSUES_SUMMARY.md
+```
+
+### 2. List All Categories
+
+```bash
+python3 scripts/view-sonar-category.py
+```
+
+### 3. View Specific Category Details
+
+```bash
+# View Security Issues (high priority)
+python3 scripts/view-sonar-category.py "Security Issues"
+
+# View with custom limit
+python3 scripts/view-sonar-category.py "Brain Methods (Complexity)" --limit 5
+```
+
+### 4. Start Interactive Fixing Session
+
+```bash
+python3 scripts/categorize-sonar-issues.py
/Users/james.bognar/Downloads/SonarQubeIssues.txt
+```
+
+## Tools
+
+### `categorize-sonar-issues.py`
+
+Main script for categorizing and interactively fixing SonarQube issues.
+
+**Usage:**
+```bash
+python3 scripts/categorize-sonar-issues.py <sonarqube-issues-file>
[--save-json]
+```
+
+**Features:**
+- Parses SonarQube TSV export file
+- Categorizes issues into 30 categories
+- Interactive session for fixing issues category by category
+- Saves categorized JSON for later reference
+
+**Options:**
+- `--save-json`: Save categorized issues to JSON file
+
+**Interactive Commands:**
+- `fix` - Start fixing issues in current category
+- `skip` - Move to next category
+- `details` - Show detailed issue information
+- `list` - List all categories
+- `<number>` - Jump to specific category number
+- `quit` - Exit
+
+### `view-sonar-category.py`
+
+Helper script to view category details without interactive input.
+
+**Usage:**
+```bash
+# List all categories
+python3 scripts/view-sonar-category.py
+
+# View specific category
+python3 scripts/view-sonar-category.py "Category Name"
+
+# View with limit
+python3 scripts/view-sonar-category.py "Category Name" --limit 10
+```
+
+## Recommended Workflow
+
+### Step 1: Review Summary
+
+Read `SONARQUBE_ISSUES_SUMMARY.md` to understand:
+- Total issues and categories
+- Priority levels
+- Recommended fix order
+
+### Step 2: Explore Categories
+
+```bash
+# List all categories
+python3 scripts/view-sonar-category.py
+
+# Review high-priority categories
+python3 scripts/view-sonar-category.py "Security Issues"
+python3 scripts/view-sonar-category.py "Null Check Issues"
+python3 scripts/view-sonar-category.py "Brain Methods (Complexity)"
+```
+
+### Step 3: Start Fixing
+
+Begin with high-priority categories:
+
+```bash
+python3 scripts/categorize-sonar-issues.py
/Users/james.bognar/Downloads/SonarQubeIssues.txt
+```
+
+Then:
+1. Navigate to high-priority categories (Security, Null Checks, Brain Methods)
+2. For each category:
+ - Review sample issues with `details`
+ - Decide on fix strategy (auto-fix vs manual review)
+ - Use `fix` to start fixing issues
+ - Process by file (recommended) or individually
+
+### Step 4: Track Progress
+
+The categorized JSON file (`SonarQubeIssues.categorized.json`) can be used to:
+- Track which categories have been fixed
+- Generate progress reports
+- Identify remaining issues
+
+## Category Priorities
+
+### High Priority (Fix First)
+- **Security Issues** (6 issues)
+- **Null Check Issues** (15 issues)
+- **Brain Methods (Complexity)** (30 issues)
+- **Missing Exception Handling** (1 issue)
+
+### Medium Priority
+- **Exception Catching Issues** (30 issues)
+- **Generic Type Issues** (121 issues)
+- **Empty Method Implementations** (99 issues)
+- **Test Assertion Issues** (61 issues)
+- **Optional Access Issues** (18 issues)
+- **Code Duplication** (16 issues)
+- **ThreadLocal Cleanup Issues** (7 issues)
+
+### Low Priority
+- **Unused Code** (96 issues)
+- **Missing Private Constructors** (91 issues)
+- All other categories
+
+## Fix Strategies
+
+### Auto-Fix Categories (Mechanical Fixes)
+These can often be fixed automatically or with simple find/replace:
+- Missing @Override Annotations
+- Unnecessary toString() Calls
+- Missing Private Constructors
+- Line Separator Issues
+- Python f-string Issues
+
+### Manual Review Categories (Require Code Review)
+These need careful review and testing:
+- Security Issues
+- Brain Methods (Complexity)
+- Null Check Issues
+- Exception Catching Issues
+- Code Duplication
+
+### Batch Fix Categories (Similar Patterns)
+These can be fixed in batches:
+- Missing Private Constructors
+- Generic Type Issues
+- Field Shadowing
+- Unused Code
+
+## Files
+
+- `SonarQubeIssues.txt` - Original SonarQube export (TSV format)
+- `SonarQubeIssues.categorized.json` - Categorized issues (JSON format)
+- `SONARQUBE_ISSUES_SUMMARY.md` - Summary document
+- `scripts/categorize-sonar-issues.py` - Main categorization tool
+- `scripts/view-sonar-category.py` - Category viewer tool
+
+## Tips
+
+1. **Start Small**: Begin with categories that have few issues to build
momentum
+2. **Batch Similar Fixes**: Group similar issues together for efficient fixing
+3. **Test After Each Category**: Run tests after fixing each category
+4. **Use Version Control**: Commit fixes category by category for easier review
+5. **Document Decisions**: For "Empty Method Implementations" and similar
categories, document why methods are intentionally empty
+
+## Example Session
+
+```bash
+# 1. View summary
+cat SONARQUBE_ISSUES_SUMMARY.md
+
+# 2. Check Security Issues (high priority, only 6 issues)
+python3 scripts/view-sonar-category.py "Security Issues"
+
+# 3. Start interactive session
+python3 scripts/categorize-sonar-issues.py
/Users/james.bognar/Downloads/SonarQubeIssues.txt
+
+# In interactive session:
+# > list # See all categories
+# > 1 # Jump to Security Issues
+# > details # See issue details
+# > fix # Start fixing
+# > [choose file mode] # Process by file
+# > auto # Auto-fix each issue
+# > skip # Move to next category
+```
+
+## Support
+
+For questions or issues with these tools, refer to:
+- `SONARQUBE_ISSUES_SUMMARY.md` - Detailed category descriptions
+- The categorized JSON file for complete issue details
diff --git a/scripts/categorize-sonar-issues.py
b/scripts/categorize-sonar-issues.py
new file mode 100755
index 0000000000..717f1aa709
--- /dev/null
+++ b/scripts/categorize-sonar-issues.py
@@ -0,0 +1,408 @@
+#!/usr/bin/env python3
+#
***************************************************************************************************************************
+# * Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file *
+# * distributed with this work for additional information regarding copyright
ownership. The ASF licenses this file *
+# * to you under the Apache License, Version 2.0 (the "License"); you may not
use this file except in compliance *
+# * with the License. You may obtain a copy of the License at
*
+# *
*
+# * http://www.apache.org/licenses/LICENSE-2.0
*
+# *
*
+# * Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an *
+# * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
express or implied. See the License for the *
+# * specific language governing permissions and limitations under the License.
*
+#
***************************************************************************************************************************
+"""
+Script to categorize and manage SonarQube issues for interactive fixing.
+"""
+
+import csv
+import re
+from collections import defaultdict
+from pathlib import Path
+from typing import Dict, List, Tuple
+import json
+
+class Issue:
+ def __init__(self, description: str, path: str, resource: str, location:
str,
+ issue_type: str, issue_id: str, creation_time: str):
+ self.description = description
+ self.path = path
+ self.resource = resource
+ self.location = location
+ self.type = issue_type
+ self.id = issue_id
+ self.creation_time = creation_time
+
+ def __repr__(self):
+ return f"Issue({self.description[:50]}... @
{self.resource}:{self.location})"
+
+def parse_issues(file_path: str) -> List[Issue]:
+ """Parse the SonarQube issues TSV file."""
+ issues = []
+ with open(file_path, 'r', encoding='utf-8') as f:
+ reader = csv.DictReader(f, delimiter='\t')
+ for row in reader:
+ issue = Issue(
+ description=row['Description'],
+ path=row['Path'],
+ resource=row['Resource'],
+ location=row['Location'],
+ issue_type=row['Type'],
+ issue_id=row['ID'],
+ creation_time=row['Creation Time']
+ )
+ issues.append(issue)
+ return issues
+
+def categorize_issue(issue: Issue) -> str:
+ """Categorize an issue based on its description."""
+ desc = issue.description.lower()
+
+ # Field shadowing issues
+ if 'is the name of a field' in desc:
+ return "Field Shadowing"
+
+ # Unnecessary toString() calls
+ if 'no need to call "tostring()"' in desc or 'already a string' in desc:
+ return "Unnecessary toString() Calls"
+
+ # Line separator issues
+ if '%n should be used' in desc or ('\\n' in desc and 'line separator' in
desc):
+ return "Line Separator Issues"
+
+ # Brain Method (complexity)
+ if 'brain method' in desc:
+ return "Brain Methods (Complexity)"
+
+ # Deprecated annotation issues
+ if 'deprecated annotation' in desc:
+ return "Deprecated Annotation Issues"
+
+ # Empty method implementations
+ if 'empty, throw' in desc or 'empty method' in desc:
+ return "Empty Method Implementations"
+
+ # Missing private constructor
+ if 'private constructor' in desc:
+ return "Missing Private Constructors"
+
+ # Missing clone() method
+ if 'clone()' in desc.lower():
+ return "Missing clone() Methods"
+
+ # Missing exception handling
+ if 'nosuchelementexception' in desc:
+ return "Missing Exception Handling"
+
+ # Empty catch blocks
+ if 'catch clause' in desc and ('logic' in desc or 'eliminate' in desc):
+ return "Empty Catch Blocks"
+
+ # Test assertion issues
+ if 'add at least one assertion' in desc or 'assertion' in desc and 'test'
in desc:
+ return "Missing Test Assertions"
+
+ # Python f-string issues
+ if 'f-string' in desc or 'replacement fields' in desc:
+ return "Python f-string Issues"
+
+ # HTML/documentation issues
+ if '<title>' in desc or 'alt' in desc.lower() or ('<th>' in desc and
'attribute' in desc):
+ return "HTML/Documentation Issues"
+
+ # String concatenation in loops
+ if 'string concatenation' in desc or ('stringbuilder' in desc and 'loop'
in desc):
+ return "String Concatenation Issues"
+
+ # Null checks
+ if 'null' in desc and ('check' in desc or 'should' in desc or 'must' in
desc):
+ return "Null Check Issues"
+
+ # Generic type issues - check more specifically
+ if 'raw type' in desc or ('generic' in desc and ('type' in desc or
'parameter' in desc)):
+ return "Generic Type Issues"
+
+ # Resource management
+ if 'close' in desc.lower() and ('resource' in desc.lower() or 'stream' in
desc.lower()):
+ return "Resource Management Issues"
+
+ # Code duplication
+ if 'duplicate' in desc.lower():
+ return "Code Duplication"
+
+ # Magic numbers
+ if 'magic number' in desc:
+ return "Magic Numbers"
+
+ # Unused code - be more specific
+ if 'unused' in desc.lower() and ('parameter' in desc or 'variable' in desc
or 'field' in desc or 'method' in desc or 'import' in desc):
+ return "Unused Code"
+
+ # Security issues
+ if 'security' in desc.lower() or 'vulnerability' in desc.lower():
+ return "Security Issues"
+
+ # Performance issues
+ if 'performance' in desc.lower() or 'inefficient' in desc.lower():
+ return "Performance Issues"
+
+ # Code smell
+ if 'code smell' in desc.lower():
+ return "Code Smells"
+
+ # Missing @Override annotations
+ if '@override' in desc or 'override annotation' in desc:
+ return "Missing @Override Annotations"
+
+ # Missing test coverage
+ if 'add some tests' in desc or 'test coverage' in desc:
+ return "Missing Test Coverage"
+
+ # Missing Javadoc tags
+ if '@deprecated' in desc.lower() and 'javadoc' in desc:
+ return "Missing Javadoc Tags"
+
+ # Singleton pattern issues
+ if 'singleton' in desc.lower():
+ return "Singleton Pattern Issues"
+
+ # Optional access issues
+ if 'optional' in desc.lower() and ('ispresent' in desc or 'isempty' in
desc or 'get()' in desc):
+ return "Optional Access Issues"
+
+ # Test assertion issues
+ if 'assertion' in desc.lower() and ('compare' in desc or 'dissimilar' in
desc or 'primitive' in desc):
+ return "Test Assertion Issues"
+
+ # Constructor visibility
+ if 'constructor' in desc.lower() and 'visibility' in desc.lower():
+ return "Constructor Visibility Issues"
+
+ # Exception catching issues
+ if 'catch' in desc.lower() and ('exception' in desc.lower() or 'throwable'
in desc.lower() or 'error' in desc.lower()):
+ return "Exception Catching Issues"
+
+ # ThreadLocal cleanup
+ if 'remove()' in desc.lower() and ('threadlocal' in desc.lower() or
'localstore' in desc.lower()):
+ return "ThreadLocal Cleanup Issues"
+
+ # Type casting issues
+ if 'cast' in desc.lower() and ('operand' in desc.lower() or
'multiplication' in desc.lower() or 'subtraction' in desc.lower()):
+ return "Type Casting Issues"
+
+ # Default category
+ return "Other Issues"
+
+def categorize_all_issues(issues: List[Issue]) -> Dict[str, List[Issue]]:
+ """Categorize all issues."""
+ categories = defaultdict(list)
+ for issue in issues:
+ category = categorize_issue(issue)
+ categories[category].append(issue)
+ return dict(categories)
+
+def print_category_summary(categories: Dict[str, List[Issue]]):
+ """Print a summary of all categories."""
+ print("\n" + "="*80)
+ print("SONARQUBE ISSUES CATEGORIZATION SUMMARY")
+ print("="*80)
+ print(f"\nTotal Issues: {sum(len(issues) for issues in
categories.values())}")
+ print(f"Total Categories: {len(categories)}\n")
+
+ # Sort by count (descending)
+ sorted_categories = sorted(categories.items(), key=lambda x: len(x[1]),
reverse=True)
+
+ print(f"{'Category':<50} {'Count':>10} {'Percentage':>10}")
+ print("-" * 80)
+
+ total = sum(len(issues) for issues in categories.values())
+ for category, issue_list in sorted_categories:
+ count = len(issue_list)
+ percentage = (count / total) * 100
+ print(f"{category:<50} {count:>10} {percentage:>9.1f}%")
+
+ print("\n" + "="*80)
+
+def print_category_details(category: str, issues: List[Issue], limit: int =
10):
+ """Print details for a specific category."""
+ print(f"\n{'='*80}")
+ print(f"CATEGORY: {category}")
+ print(f"Total Issues: {len(issues)}")
+ print(f"{'='*80}\n")
+
+ # Group by file for easier review
+ by_file = defaultdict(list)
+ for issue in issues:
+ key = f"{issue.path}/{issue.resource}"
+ by_file[key].append(issue)
+
+ print(f"Affected Files: {len(by_file)}\n")
+
+ # Show first few examples
+ print("Sample Issues (first 10):")
+ print("-" * 80)
+ for i, issue in enumerate(issues[:limit], 1):
+ print(f"{i}. {issue.description}")
+ print(f" File: {issue.path}/{issue.resource}:{issue.location}")
+ print()
+
+ if len(issues) > limit:
+ print(f"... and {len(issues) - limit} more issues\n")
+
+def save_categorized_issues(categories: Dict[str, List[Issue]], output_file:
str):
+ """Save categorized issues to a JSON file."""
+ output_data = {}
+ for category, issues in categories.items():
+ output_data[category] = [
+ {
+ 'description': issue.description,
+ 'path': issue.path,
+ 'resource': issue.resource,
+ 'location': issue.location,
+ 'type': issue.type,
+ 'id': issue.id
+ }
+ for issue in issues
+ ]
+
+ with open(output_file, 'w', encoding='utf-8') as f:
+ json.dump(output_data, f, indent=2, ensure_ascii=False)
+
+ print(f"\nCategorized issues saved to: {output_file}")
+
+def interactive_session(categories: Dict[str, List[Issue]]):
+ """Run an interactive session to work through categories."""
+ sorted_categories = sorted(categories.items(), key=lambda x: len(x[1]),
reverse=True)
+
+ print("\n" + "="*80)
+ print("INTERACTIVE SONARQUBE ISSUE FIXING SESSION")
+ print("="*80)
+ print("\nCommands:")
+ print(" <number> - Select category by number")
+ print(" list - List all categories")
+ print(" details <number> - Show details for category")
+ print(" next - Move to next category")
+ print(" quit - Exit")
+ print(" help - Show this help")
+ print("="*80)
+
+ current_index = 0
+
+ while True:
+ if current_index >= len(sorted_categories):
+ print("\nAll categories have been reviewed!")
+ break
+
+ category, issues = sorted_categories[current_index]
+ count = len(issues)
+
+ print(f"\n[{current_index + 1}/{len(sorted_categories)}] Current
Category: {category}")
+ print(f" Issues: {count}")
+ print(f"\nWhat would you like to do?")
+ print(f" - Type 'fix' to start fixing issues in this category")
+ print(f" - Type 'skip' to move to next category")
+ print(f" - Type 'details' to see issue details")
+ print(f" - Type a number to jump to that category")
+ print(f" - Type 'list' to see all categories")
+ print(f" - Type 'quit' to exit")
+
+ command = input("\n> ").strip().lower()
+
+ if command == 'quit' or command == 'q':
+ print("\nExiting. Progress saved.")
+ break
+ elif command == 'skip' or command == 'next' or command == 'n':
+ current_index += 1
+ elif command == 'details' or command == 'd':
+ print_category_details(category, issues)
+ elif command == 'list' or command == 'l':
+ print("\nCategories:")
+ for i, (cat, iss) in enumerate(sorted_categories, 1):
+ print(f" {i}. {cat} ({len(iss)} issues)")
+ elif command == 'fix' or command == 'f':
+ print(f"\nStarting fixes for category: {category}")
+ print(f"Total issues: {count}")
+ print("\nFor each issue, you can:")
+ print(" - Type 'auto' to attempt automatic fix")
+ print(" - Type 'skip' to skip this issue")
+ print(" - Type 'show' to see the code context")
+ print(" - Type 'back' to return to category selection")
+
+ # Group by file for batch processing
+ by_file = defaultdict(list)
+ for issue in issues:
+ key = f"{issue.path}/{issue.resource}"
+ by_file[key].append(issue)
+
+ print(f"\nIssues grouped into {len(by_file)} files.")
+ print("Would you like to process by file (recommended) or
individually?")
+ process_mode = input(" [f]ile/[i]ndividual (default: file):
").strip().lower() or 'f'
+
+ if process_mode == 'f':
+ for file_path, file_issues in by_file.items():
+ print(f"\n--- File: {file_path} ({len(file_issues)}
issues) ---")
+ for issue in file_issues:
+ print(f"\n Issue: {issue.description}")
+ print(f" Location: {issue.location}")
+ action = input(" Action [auto/skip/show/back]:
").strip().lower()
+ if action == 'back':
+ break
+ elif action == 'show':
+ print(f" TODO: Show code at
{file_path}:{issue.location}")
+ elif action == 'auto':
+ print(f" TODO: Auto-fix {issue.description}")
+ elif action == 'skip':
+ continue
+ else:
+ continue
+ break # Break outer loop if 'back' was used
+ else:
+ for issue in issues:
+ print(f"\n Issue: {issue.description}")
+ print(f" File:
{issue.path}/{issue.resource}:{issue.location}")
+ action = input(" Action [auto/skip/show/back]:
").strip().lower()
+ if action == 'back':
+ break
+ elif action == 'show':
+ print(f" TODO: Show code at
{issue.path}/{issue.resource}:{issue.location}")
+ elif action == 'auto':
+ print(f" TODO: Auto-fix {issue.description}")
+ elif action == 'skip':
+ continue
+ elif command.isdigit():
+ num = int(command)
+ if 1 <= num <= len(sorted_categories):
+ current_index = num - 1
+ else:
+ print(f"Invalid category number. Please enter
1-{len(sorted_categories)}")
+ else:
+ print("Unknown command. Type 'help' for available commands.")
+
+def main():
+ import sys
+
+ if len(sys.argv) < 2:
+ print("Usage: categorize-sonar-issues.py <sonarqube-issues-file>
[--save-json]")
+ sys.exit(1)
+
+ issues_file = sys.argv[1]
+ save_json = '--save-json' in sys.argv
+
+ print(f"Parsing issues from: {issues_file}")
+ issues = parse_issues(issues_file)
+ print(f"Parsed {len(issues)} issues")
+
+ print("\nCategorizing issues...")
+ categories = categorize_all_issues(issues)
+
+ print_category_summary(categories)
+
+ if save_json:
+ output_file = Path(issues_file).with_suffix('.categorized.json')
+ save_categorized_issues(categories, str(output_file))
+
+ # Start interactive session
+ interactive_session(categories)
+
+if __name__ == '__main__':
+ main()
diff --git a/scripts/view-sonar-category.py b/scripts/view-sonar-category.py
new file mode 100755
index 0000000000..cad72396ec
--- /dev/null
+++ b/scripts/view-sonar-category.py
@@ -0,0 +1,91 @@
+#!/usr/bin/env python3
+#
***************************************************************************************************************************
+# * Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file *
+# * distributed with this work for additional information regarding copyright
ownership. The ASF licenses this file *
+# * to you under the Apache License, Version 2.0 (the "License"); you may not
use this file except in compliance *
+# * with the License. You may obtain a copy of the License at
*
+# *
*
+# * http://www.apache.org/licenses/LICENSE-2.0
*
+# *
*
+# * Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an *
+# * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
express or implied. See the License for the *
+# * specific language governing permissions and limitations under the License.
*
+#
***************************************************************************************************************************
+"""
+Helper script to view SonarQube issue categories without interactive input.
+Usage: view-sonar-category.py <category-name> [--limit N]
+"""
+
+import json
+import sys
+from pathlib import Path
+
+def main():
+ json_file =
Path('/Users/james.bognar/Downloads/SonarQubeIssues.categorized.json')
+
+ if not json_file.exists():
+ print(f"Error: Categorized JSON file not found: {json_file}")
+ print("Please run categorize-sonar-issues.py first with --save-json")
+ sys.exit(1)
+
+ with open(json_file, 'r', encoding='utf-8') as f:
+ data = json.load(f)
+
+ if len(sys.argv) < 2:
+ print("Available categories:")
+ print("=" * 80)
+ sorted_cats = sorted(data.items(), key=lambda x: len(x[1]),
reverse=True)
+ for i, (category, issues) in enumerate(sorted_cats, 1):
+ print(f"{i:2d}. {category:<50} {len(issues):>5} issues")
+ sys.exit(0)
+
+ category_name = sys.argv[1]
+ limit = int(sys.argv[3]) if len(sys.argv) > 3 and sys.argv[2] == '--limit'
else 20
+
+ if category_name not in data:
+ print(f"Error: Category '{category_name}' not found.")
+ print("\nAvailable categories:")
+ for cat in sorted(data.keys()):
+ print(f" - {cat}")
+ sys.exit(1)
+
+ issues = data[category_name]
+
+ print("=" * 80)
+ print(f"CATEGORY: {category_name}")
+ print(f"Total Issues: {len(issues)}")
+ print("=" * 80)
+
+ # Group by file
+ by_file = {}
+ for issue in issues:
+ file_key = f"{issue['path']}/{issue['resource']}"
+ if file_key not in by_file:
+ by_file[file_key] = []
+ by_file[file_key].append(issue)
+
+ print(f"\nAffected Files: {len(by_file)}\n")
+
+ # Show sample issues
+ print(f"Sample Issues (showing first {min(limit, len(issues))}):")
+ print("-" * 80)
+ for i, issue in enumerate(issues[:limit], 1):
+ print(f"\n{i}. {issue['description']}")
+ print(f" File:
{issue['path']}/{issue['resource']}:{issue['location']}")
+ print(f" ID: {issue['id']}")
+
+ if len(issues) > limit:
+ print(f"\n... and {len(issues) - limit} more issues")
+
+ print("\n" + "=" * 80)
+ print("Files affected:")
+ print("-" * 80)
+ sorted_files = sorted(by_file.items(), key=lambda x: len(x[1]),
reverse=True)
+ for file_path, file_issues in sorted_files[:20]:
+ print(f" {file_path}: {len(file_issues)} issues")
+
+ if len(by_file) > 20:
+ print(f" ... and {len(by_file) - 20} more files")
+
+if __name__ == '__main__':
+ main()