Skip to content

Commit fa03ad7

Browse files
predic8rrayst
andauthored
feat: add MCExcludeFromSchema annotation and migrate statusCode t… (#2388)
* feat: add `MCExcludeFromSchema` annotation and migrate `statusCode` to `status` in YAML tutorials and schemas - Introduced `MCExcludeFromSchema` annotation to allow exclusion of fields during schema generation. - Replaced `statusCode` with `status` across YAML tutorial and schema files for consistency. - Updated `JsonSchemaGenerator` and `AttributeInfo` to support exclusion logic based on the new annotation. * refactor: remove `MCExcludeFromSchema` annotation and migrate exclusion logic to `MCAttribute` * refactor: simplify exclusion method names and streamline annotation handling in `AttributeInfo` and `JsonSchemaGenerator` * refactor: remove redundant Javadoc tags in `AttributeInfo` methods * expose 'excludeFromJson' and 'deprecated' to help reference --------- Co-authored-by: Tobias Polley <mail@tobias-polley.de> Co-authored-by: Tobias Polley <polley@predic8.de>
1 parent 7c96e7f commit fa03ad7

File tree

30 files changed

+100
-50
lines changed

30 files changed

+100
-50
lines changed

annot/src/main/java/com/predic8/membrane/annot/MCAttribute.java

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,20 @@
1919
import static java.lang.annotation.RetentionPolicy.RUNTIME;
2020

2121
/**
22-
* Injects an XML attribute using a setter method.
22+
* Annotation for marking a method to represent an attribute in the Membrane configuration.
23+
* Primarily used for defining properties and their representation across different configuration grammars,
24+
* such as JSON Schema or XML Schema (XSD).
25+
*
26+
* Methods annotated with this are typically setters with specific behavior or constraints
27+
* controlled by the annotation's attributes.
28+
*
29+
* Attributes:
30+
* - attributeName: Specifies the name of the attribute. If not defined, a default naming convention might apply.
31+
* - excludeFromJson: Indicates whether the attribute should be excluded from JSON Schema representation (default is false).
2332
*/
2433
@Target(METHOD)
2534
@Retention(RUNTIME)
2635
public @interface MCAttribute {
27-
2836
String attributeName() default "";
37+
boolean excludeFromJson() default false; // excludes from JSON Schema (YAML)
2938
}

annot/src/main/java/com/predic8/membrane/annot/generator/HelpReference.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ private void handle(Model m, MainInfo main, ElementInfo ei) throws XMLStreamExce
123123
xew.writeAttribute("mixed", "true");
124124
xew.writeAttribute("topLevel", Boolean.toString(ei.getAnnotation().topLevel()));
125125
xew.writeAttribute("id", ei.getId());
126+
xew.writeAttribute("deprecated", Boolean.toString(ei.isDeprecated()));
126127
if (!ei.getAnnotation().topLevel()) {
127128
String primaryParentId = getPrimaryParentId(m, main, ei);
128129
if (primaryParentId != null)
@@ -198,6 +199,7 @@ private void handle(Model m, MainInfo main, ChildElementInfo cei) throws XMLStre
198199
xew.writeStartElement("child");
199200
xew.writeAttribute("min", cei.isRequired() ? "1" : "0");
200201
xew.writeAttribute("max", cei.isList() ? "unbounded" : "1");
202+
xew.writeAttribute("deprecated", Boolean.toString(cei.isDeprecated()));
201203

202204
handleDoc(cei);
203205

@@ -228,6 +230,8 @@ private void handle(AttributeInfo ai) throws XMLStreamException {
228230
xew.writeStartElement("attribute");
229231
xew.writeAttribute("name", ai.getXMLName());
230232
xew.writeAttribute("required", Boolean.toString(ai.isRequired()));
233+
xew.writeAttribute("excludeFromJson", Boolean.toString(ai.excludedFromJsonSchema()));
234+
xew.writeAttribute("deprecated", Boolean.toString(ai.isDeprecated()));
231235
handleDoc(ai);
232236
xew.writeEndElement();
233237
}

annot/src/main/java/com/predic8/membrane/annot/generator/JsonSchemaGenerator.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,11 @@ private FileObject createFile(MainInfo main) throws IOException {
175175

176176
private void processMCAttributes(ElementInfo i, SchemaObject so) {
177177
i.getAis().forEach(ai -> {
178+
179+
// skip attributes marked with @MCExcludeFromSchema
180+
if (ai.excludedFromJsonSchema())
181+
return;
182+
178183
// hide id only on top-level elements
179184
if ("id".equals(ai.getXMLName()) && i.getAnnotation().topLevel()) {
180185
return;
@@ -253,7 +258,6 @@ boolean isFlowFromWebSocket(ChildElementInfo cei) {
253258
}
254259

255260
private AbstractSchema<?> processList(ElementInfo i, AbstractSchema<?> so, ChildElementInfo cei, ArrayList<SchemaObject> sos) {
256-
257261
SchemaObject items = object("items");
258262

259263
if (shouldGenerateParserType(cei)) {
@@ -293,7 +297,6 @@ private void addChildsAsProperties(Model m, MainInfo main, ChildElementInfo cei,
293297
.ref("#/$defs/" + ei.getXSDTypeName(m)))
294298
.description(getDescriptionContent(ei))
295299
.required(cei.isRequired());
296-
297300
}
298301
}
299302

annot/src/main/java/com/predic8/membrane/annot/model/AbstractJavadocedInfo.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,9 @@
1414
package com.predic8.membrane.annot.model;
1515

1616
import javax.annotation.processing.ProcessingEnvironment;
17+
import javax.lang.model.element.AnnotationMirror;
1718
import javax.lang.model.element.Element;
19+
import javax.lang.model.element.TypeElement;
1820

1921
import com.predic8.membrane.annot.MCAttribute;
2022
import com.predic8.membrane.annot.MCElement;
@@ -24,7 +26,8 @@
2426
* Common behavior of Javadoc handling for {@link MCAttribute}, {@link MCElement}, etc.
2527
*/
2628
public abstract class AbstractJavadocedInfo {
27-
private Element docedE;
29+
public static final String JAVA_LANG_DEPRECATED = "java.lang.Deprecated";
30+
private Element docedE;
2831
private boolean docGenerated;
2932
private Doc doc;
3033

@@ -50,4 +53,11 @@ public Doc getDoc(ProcessingEnvironment processingEnv) {
5053
return doc = new Doc(processingEnv, javadoc, getDocedE());
5154
}
5255

56+
public boolean isDeprecated() {
57+
for (AnnotationMirror am : docedE.getAnnotationMirrors())
58+
if (((TypeElement) am.getAnnotationType().asElement()).getQualifiedName().toString().equals(JAVA_LANG_DEPRECATED))
59+
return true;
60+
return false;
61+
}
62+
5363
}

annot/src/main/java/com/predic8/membrane/annot/model/AttributeInfo.java

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,6 @@ public String getSchemaType(Types typeUtils) {
7575
/**
7676
* It is not checked how many values the enum has. There are enums link validateRequests of OpenAPIValidator
7777
* that have more than 2 values but they are also booleans at the configuration level
78-
* @return
7978
*/
8079
private boolean isEnumBoolean(Types typeUtils) {
8180
return getEnumValues(typeUtils).contains("TRUE") && getEnumValues(typeUtils).contains("FALSE");
@@ -98,7 +97,6 @@ public boolean isBeanReference(Types typeUtils) {
9897

9998
/**
10099
* Sets as side effect instance variables e.g. xsdType, isEnum, isBeanReference.
101-
* @param typeUtils
102100
*/
103101
private void analyze(Types typeUtils) {
104102
if (xsdType != null) // already analyzed?
@@ -195,4 +193,13 @@ public boolean isRequired() {
195193
public void setRequired(boolean required) {
196194
this.required = required;
197195
}
196+
197+
/**
198+
* Determines whether the current field or method should be excluded from the JSON schema during schema generation.
199+
* @return {@code true} if the field or method is excluded from the JSON schema; {@code false} otherwise.
200+
*/
201+
public boolean excludedFromJsonSchema() {
202+
return annotation != null && annotation.excludeFromJson();
203+
}
204+
198205
}

core/src/main/java/com/predic8/membrane/core/interceptor/flow/ReturnInterceptor.java

Lines changed: 29 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939
* 2. If there is no response in the exchange, the body and contentType of the request is copied into a new response.
4040
* </p>
4141
* <p>
42-
* The options <i>statusCode</i> and <i>contentType</i> will overwrite the values from the messages.
42+
* The options <i>status</i> and <i>contentType</i> will overwrite the values from the messages.
4343
* </p>
4444
* <p>
4545
* This plugin is useful together with the template plugin. See examples/template.
@@ -51,7 +51,7 @@ public class ReturnInterceptor extends AbstractInterceptor {
5151

5252
private static final Logger log = LoggerFactory.getLogger(ReturnInterceptor.class.getName());
5353

54-
private int statusCode = 200;
54+
private int status = 200;
5555
private String contentType = null;
5656

5757
@Override
@@ -76,9 +76,9 @@ private Response getOrCreateResponse(Exchange exc) throws IOException {
7676
response = createResponseFromRequest(exc);
7777
}
7878

79-
if (statusCode != 0) {
80-
response.setStatusCode(statusCode);
81-
response.setStatusMessage(getMessageForStatusCode(statusCode));
79+
if (status != 0) {
80+
response.setStatusCode(status);
81+
response.setStatusMessage(getMessageForStatusCode(status));
8282
}
8383

8484
if (contentType!=null) {
@@ -92,7 +92,7 @@ private Response getOrCreateResponse(Exchange exc) throws IOException {
9292
}
9393

9494
private Response createResponseFromRequest(Exchange exc) throws IOException {
95-
Response.ResponseBuilder builder = new Response.ResponseBuilder().status(statusCode);
95+
Response.ResponseBuilder builder = new Response.ResponseBuilder().status(status);
9696
String reqContentType = exc.getRequest().getHeader().getContentType();
9797
if (reqContentType != null) {
9898
builder.contentType(reqContentType);
@@ -112,7 +112,7 @@ public String getDisplayName() {
112112

113113
@Override
114114
public String getShortDescription() {
115-
return (contentType != null) ? format("Sends a response with a status code of %d and a content type of %s.", statusCode, contentType) : format("Sends a response with a status code of %d.", statusCode);
115+
return (contentType != null) ? format("Sends a response with a status code of %d and a content type of %s.", status, contentType) : format("Sends a response with a status code of %d.", status);
116116
}
117117

118118
@Override
@@ -121,21 +121,38 @@ public EnumSet<Flow> getAppliedFlow() {
121121
}
122122

123123
/**
124-
* @description HTTP status code to be returned.
124+
* @deprecated Use status instead.
125+
* @description HTTP status code to be returned. statusCode is kept only for backward compatibility use status instead.
125126
* @default 200
126127
* @example 400
127128
*/
128-
@MCAttribute
129+
@Deprecated
130+
@MCAttribute(excludeFromJson = true)
129131
public void setStatusCode(int statusCode) {
130-
this.statusCode = statusCode;
132+
// Is excluded from the JSON schema. But will be included in the XSD schema.
133+
this.status = statusCode;
131134
}
132135

133136
public int getStatusCode() {
134-
return statusCode;
137+
return status;
138+
}
139+
140+
/**
141+
* @description HTTP status code to be returned.
142+
* @default 200
143+
* @example 400
144+
*/
145+
@MCAttribute
146+
public void setStatus(int status) {
147+
this.status = status;
148+
}
149+
150+
public int getStatus() {
151+
return status;
135152
}
136153

137154
/**
138-
* @description Content type of the response. If not set, the content type of the request (if available) or no content type will be used.
155+
* @description Content-Type of the response. If not set, the content type of the request (if available) or no content type will be used.
139156
* @default null
140157
* @example application/json; charset=utf-8
141158
*/

core/src/test/java/com/predic8/membrane/core/config/spring/k8s/EnvelopeTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ void routerConfConfig() {
8383
contentType: application/json
8484
src: '{ "ok": 1 }'
8585
- return:
86-
statusCode: 200
86+
status: 200
8787
---
8888
api:
8989
port: 2000

distribution/examples/extending-membrane/error-handling/custom-error-messages/apis.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ api:
104104
contentType: text/plain
105105
src: Ordinary error!
106106
- return:
107-
statusCode: 500
107+
status: 500
108108
- if:
109109
test: param.case == 'd'
110110
flow:
@@ -115,6 +115,6 @@ api:
115115
<description>XML Fehler Meldung vom Backend!</description>
116116
</failure>
117117
- return:
118-
statusCode: 500
118+
status: 500
119119
# SOAP Service Mock for Debugging
120120
- sampleSoapService: {}

distribution/examples/extending-membrane/if/apis.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,4 +69,4 @@ api:
6969
- template:
7070
src: Success
7171
- return:
72-
statusCode: 302
72+
status: 302

distribution/examples/monitoring-tracing/prometheus/apis.yaml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,20 +11,20 @@ api:
1111
port: 2001
1212
flow:
1313
- return:
14-
statusCode: 200
14+
status: 200
1515

1616
---
1717

1818
api:
1919
port: 2002
2020
flow:
2121
- return:
22-
statusCode: 404
22+
status: 404
2323

2424
---
2525

2626
api:
2727
port: 2003
2828
flow:
2929
- return:
30-
statusCode: 500
30+
status: 500

0 commit comments

Comments
 (0)