forked from loafle/openapi-generator-original
Fixes for JAXRS-CXF Codegen
This commit is contained in:
@@ -0,0 +1,120 @@
|
||||
package {{package}};
|
||||
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import javax.ws.rs.HttpMethod;
|
||||
import javax.ws.rs.Path;
|
||||
|
||||
import org.apache.cxf.jaxrs.ext.ResourceComparator;
|
||||
import org.apache.cxf.jaxrs.model.ClassResourceInfo;
|
||||
import org.apache.cxf.jaxrs.model.OperationResourceInfo;
|
||||
import org.apache.cxf.message.Message;
|
||||
|
||||
/**
|
||||
* This class only help CXF to decide which resource interface is more suitable. It used Java reflexion to iterate over Java methods but it *DO NOT* select the target method.
|
||||
*/
|
||||
public class CXFInterfaceComparator implements ResourceComparator {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(CXFInterfaceComparator.class);
|
||||
|
||||
@Override
|
||||
public int compare(ClassResourceInfo cri1, ClassResourceInfo cri2, Message message) {
|
||||
String requestVerb = (String) message.get(Message.HTTP_REQUEST_METHOD);
|
||||
String requestURI = (String) message.get(Message.REQUEST_URI);
|
||||
String requestPath = requestURI.replace((String) message.get(Message.BASE_PATH), "");
|
||||
|
||||
// remove "/"at the end of requestPath if present
|
||||
if (requestPath.endsWith("/")){
|
||||
requestPath = requestPath.substring(0, requestPath.length()-1);
|
||||
}
|
||||
|
||||
if (analyseInterface(cri1, requestPath, requestVerb)) {
|
||||
return -1; // Indicate that 'cri1' interface should be preferred
|
||||
} else if (analyseInterface(cri2, requestPath, requestVerb)) {
|
||||
return 1; // Indicate that 'cri2' interface should be preferred
|
||||
} else {
|
||||
return 0; // Nothing match, leave CXF decision
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Analyse each methods provided to check if there is a match with the
|
||||
* message request path and request HTTP verb.
|
||||
*
|
||||
* @param cri
|
||||
* the interface to be analysed
|
||||
* @param requestPath
|
||||
* the path of the request. Do not contains the host and base
|
||||
* path
|
||||
* @return true if a method match the request, false otherwise
|
||||
*/
|
||||
private static boolean analyseInterface(ClassResourceInfo cri, String requestPath, String requestVerb) {
|
||||
assert cri.getServiceClass() != null;
|
||||
assert cri.getServiceClass().getInterfaces() != null;
|
||||
assert cri.getServiceClass().getInterfaces()[0] != null;
|
||||
assert cri.getServiceClass().getInterfaces()[0].getMethods().length > 0;
|
||||
|
||||
Method[] methods = cri.getServiceClass().getInterfaces()[0].getMethods();
|
||||
// Java reflexion. Check all the methods of an interface.
|
||||
for (Method method : methods) {
|
||||
Path pathAnnotation = method.getAnnotation(javax.ws.rs.Path.class);
|
||||
if (pathAnnotation != null && pathAnnotation.value() != null) {
|
||||
String pathValue = pathAnnotation.value();
|
||||
String methodHttpVerb = getMethodHttpVerb(method);
|
||||
|
||||
// Always authorize OPTIONS request if the path is matching a method declaration
|
||||
if (requestVerb.equals(HttpMethod.OPTIONS) && match(pathValue,requestPath)) {
|
||||
return true;
|
||||
}
|
||||
// Also check the HTTP verb since a single path can be match do multiple request, depending of the HTTP request verb.
|
||||
if (requestVerb.equals(methodHttpVerb) && match(pathValue, requestPath)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static String getMethodHttpVerb(Method method) {
|
||||
if (method.getAnnotation(javax.ws.rs.POST.class) != null) {
|
||||
return HttpMethod.POST;
|
||||
} else if (method.getAnnotation(javax.ws.rs.GET.class) != null) {
|
||||
return HttpMethod.GET;
|
||||
} else if (method.getAnnotation(javax.ws.rs.PUT.class) != null) {
|
||||
return HttpMethod.PUT;
|
||||
} else if (method.getAnnotation(javax.ws.rs.OPTIONS.class) != null) {
|
||||
return HttpMethod.OPTIONS;
|
||||
} else if (method.getAnnotation(javax.ws.rs.DELETE.class) != null) {
|
||||
return HttpMethod.DELETE;
|
||||
} else if (method.getAnnotation(javax.ws.rs.HEAD.class) != null) {
|
||||
return HttpMethod.HEAD;
|
||||
}
|
||||
assert false;
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether if the pathValue match with the requestPath parameter.
|
||||
* Every path params are considered to be declared as '{param}'. The tokens to start and close path params declaration are '{' and '}'.
|
||||
*
|
||||
* @param valueFromAnnotation
|
||||
* @param valueFromRequest
|
||||
* @return true if there is a match, false otherwise
|
||||
*/
|
||||
private static boolean match(String valueFromAnnotation, String valueFromRequest) {
|
||||
String patternFinal = valueFromAnnotation.replaceAll("\\{(.*?)\\}", "([^/]*)").replace("/", "\\/");
|
||||
Matcher matcher = Pattern.compile(patternFinal).matcher(valueFromRequest);
|
||||
if (matcher.matches()) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compare(OperationResourceInfo ori1, OperationResourceInfo ori2, Message message) {
|
||||
return 0; // Leave CXF decision
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@ package {{package}};
|
||||
import javax.ws.rs.*;
|
||||
import javax.ws.rs.core.Response;
|
||||
|
||||
@Path("{{contextPath}}")
|
||||
@Path("/")
|
||||
public interface {{classname}} {
|
||||
{{#operations}}
|
||||
{{#operation}}
|
||||
@@ -14,8 +14,7 @@ public interface {{classname}} {
|
||||
{{#subresourceOperation}}@Path("{{path}}"){{/subresourceOperation}}
|
||||
{{#hasConsumes}}@Consumes({ {{#consumes}}"{{mediaType}}"{{#hasMore}}, {{/hasMore}}{{/consumes}} }){{/hasConsumes}}
|
||||
{{#hasProduces}}@Produces({ {{#produces}}"{{mediaType}}"{{#hasMore}}, {{/hasMore}}{{/produces}} }){{/hasProduces}}
|
||||
public Response {{nickname}}({{#allParams}}{{>queryParams}}{{>pathParams}}{{>headerParams}}{{>bodyParams}}{{>formParams}}{{#hasMore}},
|
||||
{{/hasMore}}{{/allParams}});
|
||||
public Response {{nickname}}({{#allParams}}{{>queryParams}}{{>pathParams}}{{>headerParams}}{{>bodyParams}}{{>formParams}}{{#hasMore}},{{/hasMore}}{{/allParams}});
|
||||
{{/operation}}
|
||||
}
|
||||
{{/operations}}
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
package {{package}};
|
||||
|
||||
{{#imports}}import {{import}};
|
||||
{{/imports}}
|
||||
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
|
||||
{{#models}}
|
||||
|
||||
{{#model}}{{#description}}
|
||||
/**
|
||||
* {{description}}
|
||||
**/{{/description}}
|
||||
@XmlRootElement(name="{{classname}}")
|
||||
public class {{classname}} {{#parent}}extends {{{parent}}}{{/parent}} {
|
||||
{{#vars}}
|
||||
{{#isEnum}}
|
||||
public enum {{datatypeWithEnum}} {
|
||||
{{#allowableValues}}{{#values}} {{.}}, {{/values}}{{/allowableValues}}
|
||||
};
|
||||
private {{{datatypeWithEnum}}} {{name}} = {{{defaultValue}}};{{/isEnum}}{{^isEnum}}
|
||||
private {{{datatype}}} {{name}} = {{{defaultValue}}};{{/isEnum}}{{/vars}}
|
||||
|
||||
{{#vars}}
|
||||
/**{{#description}}
|
||||
* {{{description}}}{{/description}}{{#minimum}}
|
||||
* minimum: {{minimum}}{{/minimum}}{{#maximum}}
|
||||
* maximum: {{maximum}}{{/maximum}}
|
||||
**/
|
||||
@JsonProperty("{{name}}")
|
||||
public {{{datatypeWithEnum}}} {{getter}}() {
|
||||
return {{name}};
|
||||
}
|
||||
public void {{setter}}({{{datatypeWithEnum}}} {{name}}) {
|
||||
this.{{name}} = {{name}};
|
||||
}
|
||||
|
||||
{{/vars}}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("class {{classname}} {\n");
|
||||
{{#parent}}sb.append(" " + super.toString()).append("\n");{{/parent}}
|
||||
{{#vars}}sb.append(" {{name}}: ").append({{name}}).append("\n");
|
||||
{{/vars}}sb.append("}\n");
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
{{/model}}
|
||||
{{/models}}
|
||||
@@ -1,3 +1,16 @@
|
||||
import javax.xml.bind.annotation.XmlEnum;
|
||||
import javax.xml.bind.annotation.XmlType;
|
||||
|
||||
@XmlType(name="{{classNameFirstLetterLower}}")
|
||||
@XmlEnum
|
||||
public enum {{classname}} {
|
||||
{{#allowableValues}}{{.}}{{^-last}}, {{/-last}}{{/allowableValues}}
|
||||
{{#allowableValues}}{{.}}{{^-last}}, {{/-last}}{{#-last}};{{/-last}}{{/allowableValues}}
|
||||
|
||||
public String value() {
|
||||
return name();
|
||||
}
|
||||
|
||||
public static {{classname}} fromValue(String v) {
|
||||
return valueOf(v);
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,8 @@
|
||||
package {{package}};
|
||||
|
||||
{{#imports}}import{{import}};
|
||||
{{#imports}}import {{import}};
|
||||
{{/imports}}
|
||||
|
||||
{{#serializableModel}}import java.io.Serializable;{{/serializableModel}}
|
||||
{{#models}}
|
||||
{{#model}}{{#description}}
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
import javax.xml.bind.annotation.XmlElement;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
import javax.xml.bind.annotation.XmlAccessType;
|
||||
import javax.xml.bind.annotation.XmlAccessorType;
|
||||
import javax.xml.bind.annotation.XmlType;
|
||||
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
{{#hasVars}} @XmlType(name = "{{classn,ame}}", propOrder =
|
||||
{ {{#vars}}"{{name}}"{{^-last}}, {{/-last}}{{/vars}}
|
||||
}){{/hasVars}}
|
||||
{{^hasVars}}@XmlType(name = "{{classname}}"){{/hasVars}}
|
||||
{{^parent}}@XmlRootElement(name="{{classname}}"){{/parent}}
|
||||
public class {{classname}} {{#parent}}extends {{{parent}}}{{/parent}} {
|
||||
{{#vars}}{{#isEnum}}
|
||||
|
||||
{{>enumClass}}{{/isEnum}}{{#items.isEnum}}{{#items}}
|
||||
|
||||
{{>enumClass}}{{/items}}{{/items.isEnum}}
|
||||
|
||||
private {{{datatypeWithEnum}}} {{name}} = {{{defaultValue}}};{{/vars}}
|
||||
|
||||
{{#vars}}
|
||||
/**{{#description}}
|
||||
* {{{description}}}{{/description}}{{#minimum}}
|
||||
* minimum: {{minimum}}{{/minimum}}{{#maximum}}
|
||||
* maximum: {{maximum}}{{/maximum}}
|
||||
**/
|
||||
{{#vendorExtensions.extraAnnotation}}{{vendorExtensions.extraAnnotation}}{{/vendorExtensions.extraAnnotation}}
|
||||
public {{{datatypeWithEnum}}} {{getter}}() {
|
||||
return {{name}};
|
||||
}
|
||||
public void {{setter}}({{{datatypeWithEnum}}} {{name}}) {
|
||||
this.{{name}} = {{name}};
|
||||
}
|
||||
{{/vars}}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("class {{classname}} {\n");
|
||||
{{#parent}}sb.append(" ").append(toIndentedString(super.toString())).append("\n");{{/parent}}
|
||||
{{#vars}}sb.append(" {{name}}: ").append(toIndentedString({{name}})).append("\n");
|
||||
{{/vars}}sb.append("}");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the given object to string with each line indented by 4 spaces
|
||||
* (except the first line).
|
||||
*/
|
||||
private static String toIndentedString(Object o) {
|
||||
if (o == null) {
|
||||
return "null";
|
||||
}
|
||||
return o.toString().replace("\n", "\n ");
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
sbt.version=0.12.0
|
||||
Reference in New Issue
Block a user