From 4a5edbe3f6c4aa6123c837a0303f86a5dfe7f53b Mon Sep 17 00:00:00 2001 From: Marco Nembrini Date: Thu, 12 Jul 2018 10:54:59 +0200 Subject: [PATCH] Feature/query parameter required (#12) * add support for required=false in query parameter for spring boot generator * add clarifying TODOs for missing functionality --- .../builder/AbstractResourceBuilder.java | 13 +- .../restapi/builder/MethodContext.groovy | 8 +- .../restapi/builder/ResourceBuilder.java | 28 +- .../jaxrs/JaxRsRootResourceFactory.groovy | 6 +- .../spring/SpringRootResourceFactory.java | 196 ++++++----- .../ProductproposalResource.java.txt | 3 +- .../rest/contract/model/v1/VerbParameter.java | 328 +++++++++--------- 7 files changed, 307 insertions(+), 275 deletions(-) diff --git a/gradle-plugin/src/main/groovy/ch/silviowangler/gradle/restapi/builder/AbstractResourceBuilder.java b/gradle-plugin/src/main/groovy/ch/silviowangler/gradle/restapi/builder/AbstractResourceBuilder.java index 8061d841..a3a8a4e3 100644 --- a/gradle-plugin/src/main/groovy/ch/silviowangler/gradle/restapi/builder/AbstractResourceBuilder.java +++ b/gradle-plugin/src/main/groovy/ch/silviowangler/gradle/restapi/builder/AbstractResourceBuilder.java @@ -35,6 +35,7 @@ import java.time.LocalDate; import java.time.LocalDateTime; import java.util.*; +import java.util.function.Function; import java.util.stream.Collectors; import static ch.silviowangler.gradle.restapi.PluginTypes.*; @@ -67,10 +68,12 @@ protected void setCurrentVerb(Verb currentVerb) { this.currentVerb = currentVerb; } + @Override public String getCurrentPackageName() { return currentPackageName; } + @Override public ArtifactType getArtifactType() { return artifactType; } @@ -172,10 +175,10 @@ public void generateResourceMethods() { MethodSpec.Builder methodBuilder; - Map params = new HashMap<>(); this.currentVerb = verb; - verb.getParameters().forEach(p -> params.put(p.getName(), GeneratorUtil.translateToJava(p.getType()))); + Map params = verb.getParameters().stream().collect(Collectors.toMap(VerbParameter::getName, Function.identity())); + Map paramClasses = new HashMap<>(); for (Representation representation : verb.getRepresentations()) { @@ -183,7 +186,7 @@ public void generateResourceMethods() { List pathParams = getPathParams(parser, isAbstractOrInterfaceResource()); - MethodContext context = new MethodContext(resourceMethodReturnType(verb, representation), params, representation, pathParams, directEntity); + MethodContext context = new MethodContext(resourceMethodReturnType(verb, representation), params, paramClasses, representation, pathParams, directEntity); if (GenerateRestApiTask.GET_COLLECTION.equals(verb.getVerb())) { @@ -204,14 +207,14 @@ public void generateResourceMethods() { if (GenerateRestApiTask.POST.equals(verb.getVerb())) { - params.put("model", model); + paramClasses.put("model", model); context.setMethodName("createEntity"); methodBuilder = createMethod(context); } else if (GenerateRestApiTask.PUT.equals(verb.getVerb())) { - params.put("model", model); + paramClasses.put("model", model); context.setMethodName("updateEntity"); methodBuilder = createMethod(context); diff --git a/gradle-plugin/src/main/groovy/ch/silviowangler/gradle/restapi/builder/MethodContext.groovy b/gradle-plugin/src/main/groovy/ch/silviowangler/gradle/restapi/builder/MethodContext.groovy index 48fe7eb5..70b7c93e 100644 --- a/gradle-plugin/src/main/groovy/ch/silviowangler/gradle/restapi/builder/MethodContext.groovy +++ b/gradle-plugin/src/main/groovy/ch/silviowangler/gradle/restapi/builder/MethodContext.groovy @@ -24,6 +24,7 @@ package ch.silviowangler.gradle.restapi.builder import ch.silviowangler.rest.contract.model.v1.Representation +import ch.silviowangler.rest.contract.model.v1.VerbParameter import com.squareup.javapoet.ClassName import com.squareup.javapoet.ParameterSpec import com.squareup.javapoet.TypeName @@ -35,7 +36,8 @@ class MethodContext { String methodName TypeName returnType - Map params = [:] + Map params = [:] + Map paramClasses = [:] Representation representation List pathParams = [] boolean directEntity @@ -46,11 +48,13 @@ class MethodContext { this.representation = representation } - MethodContext(TypeName returnType, Map params, Representation representation, List pathParams, boolean directEntity) { + MethodContext(TypeName returnType, Map params, Map paramClasses, Representation representation, List pathParams, boolean directEntity) { this.returnType = returnType this.params = params this.representation = representation this.pathParams = pathParams this.directEntity = directEntity + this.paramClasses = paramClasses + } } diff --git a/gradle-plugin/src/main/groovy/ch/silviowangler/gradle/restapi/builder/ResourceBuilder.java b/gradle-plugin/src/main/groovy/ch/silviowangler/gradle/restapi/builder/ResourceBuilder.java index 62c4c515..5cb1125d 100644 --- a/gradle-plugin/src/main/groovy/ch/silviowangler/gradle/restapi/builder/ResourceBuilder.java +++ b/gradle-plugin/src/main/groovy/ch/silviowangler/gradle/restapi/builder/ResourceBuilder.java @@ -28,6 +28,7 @@ import ch.silviowangler.gradle.restapi.RestApiPlugin; import ch.silviowangler.rest.contract.model.v1.Representation; import ch.silviowangler.rest.contract.model.v1.Verb; +import ch.silviowangler.rest.contract.model.v1.VerbParameter; import com.google.common.base.CaseFormat; import com.squareup.javapoet.*; @@ -207,9 +208,26 @@ default MethodSpec.Builder createMethod(MethodContext context) { List names = new ArrayList<>(context.getParams().size()); - context.getParams().forEach((name, type) -> { + context.getParams().forEach((name, p) -> { - ParameterSpec.Builder builder = ParameterSpec.builder(type, name); + ParameterSpec.Builder builder = ParameterSpec.builder(GeneratorUtil.translateToJava(p.getType()), name); + + final boolean isHandleMethod = methodNameCopy.startsWith("handle"); + final boolean isResource = isResourceInterface || isAbstractResourceClass; + + if (isResource && !isHandleMethod) { + builder.addAnnotation(getQueryParamAnnotation(p)); + } + + ParameterSpec parameter = builder.build(); + + methodBuilder.addParameter(parameter); + names.add(name); + }); + + context.getParamClasses().forEach((name, className) -> { + + ParameterSpec.Builder builder = ParameterSpec.builder(className, name); final boolean isHandleMethod = methodNameCopy.startsWith("handle"); final boolean isResource = isResourceInterface || isAbstractResourceClass; @@ -220,8 +238,6 @@ default MethodSpec.Builder createMethod(MethodContext context) { if (providesRequestBodyAnnotation()) { builder.addAnnotation(buildRequestBodyAnnotation()); } - } else if (isResource && !isHandleMethod) { - builder.addAnnotation(getQueryParamAnnotation(name)); } ParameterSpec parameter = builder.build(); @@ -230,7 +246,7 @@ default MethodSpec.Builder createMethod(MethodContext context) { names.add(name); }); - if (!context.isDirectEntity() && methodName.matches("(handle){0,1}(get|update|delete|Get|Update|Delete)Entity.*")) { + if (!context.isDirectEntity() && methodName.matches("(handle){0,1}(get|update|delete|Get|Update|Delete)Entity.*")) { ParameterSpec id = generateIdParam(generateIdParamAnnotation); methodBuilder.addParameter(id); names.add(id.name); @@ -270,7 +286,7 @@ default boolean isDefaultMethodNotAllowed(String methodName) { return methodName.endsWith("AutoAnswer") && ArtifactType.RESOURCE.equals(getArtifactType()); } - AnnotationSpec getQueryParamAnnotation(String paramName); + AnnotationSpec getQueryParamAnnotation(VerbParameter paramName); Iterable getResourceMethodAnnotations(boolean applyId, Representation representation, String methodName); diff --git a/gradle-plugin/src/main/groovy/ch/silviowangler/gradle/restapi/builder/jaxrs/JaxRsRootResourceFactory.groovy b/gradle-plugin/src/main/groovy/ch/silviowangler/gradle/restapi/builder/jaxrs/JaxRsRootResourceFactory.groovy index 7b42c0ec..9eb30621 100644 --- a/gradle-plugin/src/main/groovy/ch/silviowangler/gradle/restapi/builder/jaxrs/JaxRsRootResourceFactory.groovy +++ b/gradle-plugin/src/main/groovy/ch/silviowangler/gradle/restapi/builder/jaxrs/JaxRsRootResourceFactory.groovy @@ -29,6 +29,7 @@ import ch.silviowangler.gradle.restapi.builder.AbstractResourceBuilder import ch.silviowangler.gradle.restapi.builder.ArtifactType import ch.silviowangler.rest.contract.model.v1.Representation import ch.silviowangler.rest.contract.model.v1.Verb +import ch.silviowangler.rest.contract.model.v1.VerbParameter import com.squareup.javapoet.* import java.nio.charset.Charset @@ -111,8 +112,9 @@ class JaxRsRootResourceFactory extends AbstractResourceBuilder { @Override - AnnotationSpec getQueryParamAnnotation(String paramName) { - return createAnnotation(JAX_RS_QUERY_PARAM, ['value': paramName]) + AnnotationSpec getQueryParamAnnotation(VerbParameter paramName) { + // TODO handle VerbParameter options like required + return createAnnotation(JAX_RS_QUERY_PARAM, ['value': paramName.getName()]) } @Override diff --git a/gradle-plugin/src/main/groovy/ch/silviowangler/gradle/restapi/builder/spring/SpringRootResourceFactory.java b/gradle-plugin/src/main/groovy/ch/silviowangler/gradle/restapi/builder/spring/SpringRootResourceFactory.java index 41179390..ab6e5547 100644 --- a/gradle-plugin/src/main/groovy/ch/silviowangler/gradle/restapi/builder/spring/SpringRootResourceFactory.java +++ b/gradle-plugin/src/main/groovy/ch/silviowangler/gradle/restapi/builder/spring/SpringRootResourceFactory.java @@ -29,6 +29,7 @@ import ch.silviowangler.gradle.restapi.builder.ArtifactType; import ch.silviowangler.rest.contract.model.v1.Representation; import ch.silviowangler.rest.contract.model.v1.Verb; +import ch.silviowangler.rest.contract.model.v1.VerbParameter; import com.squareup.javapoet.*; import java.nio.charset.Charset; @@ -38,55 +39,55 @@ public class SpringRootResourceFactory extends AbstractResourceBuilder { - private static final ClassName STRING_CLASS = ClassName.get(String.class); + private static final ClassName STRING_CLASS = ClassName.get(String.class); - @Override - public boolean supportsInterfaces() { - return false; - } + @Override + public boolean supportsInterfaces() { + return false; + } - @Override - public TypeSpec buildResource() { - reset(); - setArtifactType(ArtifactType.ABSTRACT_RESOURCE); - TypeSpec.Builder resourceBuilder = resourceBaseTypeBuilder(); + @Override + public TypeSpec buildResource() { + reset(); + setArtifactType(ArtifactType.ABSTRACT_RESOURCE); + TypeSpec.Builder resourceBuilder = resourceBaseTypeBuilder(); - Map args = new HashMap<>(); - args.put("value", getPath()); + Map args = new HashMap<>(); + args.put("value", getPath()); - resourceBuilder.addAnnotation(createAnnotation(SPRING_REQUEST_MAPPING, args)); + resourceBuilder.addAnnotation(createAnnotation(SPRING_REQUEST_MAPPING, args)); - generateResourceMethods(); - return resourceBuilder.build(); - } + generateResourceMethods(); + return resourceBuilder.build(); + } - @Override - public TypeSpec buildResourceImpl() { - reset(); - setArtifactType(ArtifactType.RESOURCE_IMPL); - TypeSpec.Builder builder = classBaseInstance(); + @Override + public TypeSpec buildResourceImpl() { + reset(); + setArtifactType(ArtifactType.RESOURCE_IMPL); + TypeSpec.Builder builder = classBaseInstance(); - builder.addAnnotation(createAnnotation(SPRING_REST_CONTROLLER)); - builder.superclass(ClassName.get(getCurrentPackageName(), resourceName())); + builder.addAnnotation(createAnnotation(SPRING_REST_CONTROLLER)); + builder.superclass(ClassName.get(getCurrentPackageName(), resourceName())); - generateResourceMethods(); - return builder.build(); - } + generateResourceMethods(); + return builder.build(); + } - @Override - protected void createOptionsMethod() { + @Override + protected void createOptionsMethod() { - Verb verb = new Verb(); - verb.setVerb("OPTIONS"); + Verb verb = new Verb(); + verb.setVerb("OPTIONS"); - setCurrentVerb(verb); - MethodSpec.Builder optionsMethod = createMethod("getOptions", STRING_CLASS); + setCurrentVerb(verb); + MethodSpec.Builder optionsMethod = createMethod("getOptions", STRING_CLASS); - optionsMethod.addStatement("return OPTIONS_CONTENT"); + optionsMethod.addStatement("return OPTIONS_CONTENT"); - resourceBaseTypeBuilder().addMethod(optionsMethod.build()); - setCurrentVerb(null); - } + resourceBaseTypeBuilder().addMethod(optionsMethod.build()); + setCurrentVerb(null); + } @Override public boolean providesRequestBodyAnnotation() { @@ -99,48 +100,55 @@ public AnnotationSpec buildRequestBodyAnnotation() { } @Override - public AnnotationSpec getQueryParamAnnotation(String paramName) { - return AnnotationSpec.builder(SPRING_REQUEST_PARAM.getClassName()) - .addMember("value", "$S", paramName).build(); - } + public AnnotationSpec getQueryParamAnnotation(VerbParameter param) { + AnnotationSpec.Builder builder = AnnotationSpec.builder(SPRING_REQUEST_PARAM.getClassName()) + .addMember("value", "$S", param.getName()); - @Override - public Iterable getResourceMethodAnnotations(boolean applyId, Representation representation, String methodName) { - List annotations = new ArrayList<>(); + if (!param.getMandatory()) { + builder.addMember("required", "$L", false); + } + // TODO handle other VerbParameter options like defaultValue - String httpMethod = getHttpMethod(); + return builder.build(); + } + + @Override + public Iterable getResourceMethodAnnotations(boolean applyId, Representation representation, String methodName) { + List annotations = new ArrayList<>(); - AnnotationSpec.Builder builder = AnnotationSpec.builder(SPRING_REQUEST_MAPPING.getClassName()); + String httpMethod = getHttpMethod(); - builder.addMember("method", "$T." + httpMethod.toUpperCase(), SPRING_REQUEST_METHOD.getClassName()); + AnnotationSpec.Builder builder = AnnotationSpec.builder(SPRING_REQUEST_MAPPING.getClassName()); - if (applyId) { - if (representation.isJson()) { - builder.addMember("path", "\"/{$L}\"", "id"); - } else { - builder.addMember("path", "\"/{$L}.$L\"", "id", representation.getName()); - } - } + builder.addMember("method", "$T." + httpMethod.toUpperCase(), SPRING_REQUEST_METHOD.getClassName()); - if (representation.isJson() && getResponseEncoding() != null) { + if (applyId) { + if (representation.isJson()) { + builder.addMember("path", "\"/{$L}\"", "id"); + } else { + builder.addMember("path", "\"/{$L}.$L\"", "id", representation.getName()); + } + } - if (Charset.forName("UTF-8").equals(getResponseEncoding())) { - builder.addMember("produces", "$T.APPLICATION_JSON_UTF8_VALUE", SPRING_HTTP_MEDIA_TYPE.getClassName()); - } else { - builder.addMember("produces", "application/json;charset=$L", getResponseEncoding().name()); - } + if (representation.isJson() && getResponseEncoding() != null) { - } else if (representation.isJson()) { - builder.addMember("produces", "$T.APPLICATION_JSON_VALUE", SPRING_HTTP_MEDIA_TYPE.getClassName()); - } else { - builder.addMember("produces", "$S", representation.getMimetype()); - } + if (Charset.forName("UTF-8").equals(getResponseEncoding())) { + builder.addMember("produces", "$T.APPLICATION_JSON_UTF8_VALUE", SPRING_HTTP_MEDIA_TYPE.getClassName()); + } else { + builder.addMember("produces", "application/json;charset=$L", getResponseEncoding().name()); + } - annotations.add(builder.build()); + } else if (representation.isJson()) { + builder.addMember("produces", "$T.APPLICATION_JSON_VALUE", SPRING_HTTP_MEDIA_TYPE.getClassName()); + } else { + builder.addMember("produces", "$S", representation.getMimetype()); + } - if (representation.isJson()) { - annotations.add(createAnnotation(SPRING_RESPONSE_BODY)); - } + annotations.add(builder.build()); + + if (representation.isJson()) { + annotations.add(createAnnotation(SPRING_RESPONSE_BODY)); + } List responseStatusRequired = Arrays.asList("createEntity", "deleteEntity", "deleteCollection"); @@ -149,11 +157,9 @@ public Iterable getResourceMethodAnnotations(boolean applyId, Re String v; if (methodName.startsWith("create")) { v = "$T.CREATED"; - } - else if (methodName.startsWith("delete")) { + } else if (methodName.startsWith("delete")) { v = "$T.NO_CONTENT"; - } - else { + } else { throw new IllegalArgumentException("Unknown method name " + methodName); } @@ -162,27 +168,27 @@ else if (methodName.startsWith("delete")) { annotations.add(b.build()); } - return annotations; - } - - @Override - public PluginTypes getPathVariableAnnotationType() { - return SPRING_PATH_VARIABLE; - } - - @Override - public void generateMethodNotAllowedStatement(MethodSpec.Builder builder) { - builder.addStatement("return new $T<>($T.METHOD_NOT_ALLOWED)", getMethodNowAllowedReturnType(), SPRING_HTTP_STATUS.getClassName()); - } - - @Override - public ClassName getMethodNowAllowedReturnType() { - return SPRING_RESPONSE_ENTITY.getClassName(); - } - - @Override - public TypeName resourceMethodReturnType(Verb verb, Representation representation) { - String v = toHttpMethod(verb); - return GeneratorUtil.getSpringBootReturnType(getResourceContractContainer().getSourceFileName(), v, false, getCurrentPackageName(), representation); - } + return annotations; + } + + @Override + public PluginTypes getPathVariableAnnotationType() { + return SPRING_PATH_VARIABLE; + } + + @Override + public void generateMethodNotAllowedStatement(MethodSpec.Builder builder) { + builder.addStatement("return new $T<>($T.METHOD_NOT_ALLOWED)", getMethodNowAllowedReturnType(), SPRING_HTTP_STATUS.getClassName()); + } + + @Override + public ClassName getMethodNowAllowedReturnType() { + return SPRING_RESPONSE_ENTITY.getClassName(); + } + + @Override + public TypeName resourceMethodReturnType(Verb verb, Representation representation) { + String v = toHttpMethod(verb); + return GeneratorUtil.getSpringBootReturnType(getResourceContractContainer().getSourceFileName(), v, false, getCurrentPackageName(), representation); + } } diff --git a/gradle-plugin/src/test/resources/javaOutput/proposal-spring-boot/ProductproposalResource.java.txt b/gradle-plugin/src/test/resources/javaOutput/proposal-spring-boot/ProductproposalResource.java.txt index 391e6870..97a3b467 100644 --- a/gradle-plugin/src/test/resources/javaOutput/proposal-spring-boot/ProductproposalResource.java.txt +++ b/gradle-plugin/src/test/resources/javaOutput/proposal-spring-boot/ProductproposalResource.java.txt @@ -39,7 +39,8 @@ public abstract class ProductproposalResource { produces = MediaType.APPLICATION_JSON_VALUE ) @ResponseBody - public Collection getCollection(@RequestParam("q") String q) { + public Collection getCollection( + @RequestParam(value = "q", required = false) String q) { return handleGetCollection(q); } diff --git a/json-model/src/main/java/ch/silviowangler/rest/contract/model/v1/VerbParameter.java b/json-model/src/main/java/ch/silviowangler/rest/contract/model/v1/VerbParameter.java index 77a903ca..06e9363e 100644 --- a/json-model/src/main/java/ch/silviowangler/rest/contract/model/v1/VerbParameter.java +++ b/json-model/src/main/java/ch/silviowangler/rest/contract/model/v1/VerbParameter.java @@ -32,168 +32,168 @@ */ public class VerbParameter implements Serializable { - private String name; - private String type; - private String options; - private boolean mandatory; - private Number min; - private Number max; - private boolean multiple; - private Object defaultValue; - // in JSON protected - private String shield; - private boolean visible; - private boolean sortable; - private boolean readonly; - private boolean filterable; - private List alias; - private String xComment; - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getType() { - return type; - } - - public void setType(String type) { - this.type = type; - } - - public String getOptions() { - return options; - } - - public void setOptions(String options) { - this.options = options; - } - - public boolean getMandatory() { - return mandatory; - } - - public void setMandatory(boolean mandatory) { - this.mandatory = mandatory; - } - - public Number getMin() { - return min; - } - - public void setMin(Number min) { - this.min = min; - } - - public Number getMax() { - return max; - } - - public void setMax(Number max) { - this.max = max; - } - - public boolean isMultiple() { - return multiple; - } - - public void setMultiple(boolean multiple) { - this.multiple = multiple; - } - - public Object getDefaultValue() { - return defaultValue; - } - - public void setDefaultValue(Object defaultValue) { - this.defaultValue = defaultValue; - } - - public String getShield() { - return shield; - } - - public void setShield(String shield) { - this.shield = shield; - } - - public boolean isVisible() { - return visible; - } - - public void setVisible(boolean visible) { - this.visible = visible; - } - - public boolean isSortable() { - return sortable; - } - - public void setSortable(boolean sortable) { - this.sortable = sortable; - } - - public boolean isReadonly() { - return readonly; - } - - public void setReadonly(boolean readonly) { - this.readonly = readonly; - } - - public boolean isFilterable() { - return filterable; - } - - public void setFilterable(boolean filterable) { - this.filterable = filterable; - } - - public List getAlias() { - return alias; - } - - public void setAlias(List alias) { - this.alias = alias; - } - - public String getxComment() { - return xComment; - } - - public void setxComment(String xComment) { - this.xComment = xComment; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - VerbParameter that = (VerbParameter) o; - return mandatory == that.mandatory && - multiple == that.multiple && - visible == that.visible && - sortable == that.sortable && - readonly == that.readonly && - filterable == that.filterable && - Objects.equals(name, that.name) && - Objects.equals(type, that.type) && - Objects.equals(options, that.options) && - Objects.equals(min, that.min) && - Objects.equals(max, that.max) && - Objects.equals(defaultValue, that.defaultValue) && - Objects.equals(shield, that.shield) && - Objects.equals(alias, that.alias) && - Objects.equals(xComment, that.xComment); - } - - @Override - public int hashCode() { - - return Objects.hash(name, type, options, mandatory, min, max, multiple, defaultValue, shield, visible, sortable, readonly, filterable, alias, xComment); - } + private String name; + private String type; + private String options; + private boolean mandatory; + private Number min; + private Number max; + private boolean multiple; + private Object defaultValue; + // in JSON protected + private String shield; + private boolean visible; + private boolean sortable; + private boolean readonly; + private boolean filterable; + private List alias; + private String xComment; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String getOptions() { + return options; + } + + public void setOptions(String options) { + this.options = options; + } + + public boolean getMandatory() { + return mandatory; + } + + public void setMandatory(boolean mandatory) { + this.mandatory = mandatory; + } + + public Number getMin() { + return min; + } + + public void setMin(Number min) { + this.min = min; + } + + public Number getMax() { + return max; + } + + public void setMax(Number max) { + this.max = max; + } + + public boolean isMultiple() { + return multiple; + } + + public void setMultiple(boolean multiple) { + this.multiple = multiple; + } + + public Object getDefaultValue() { + return defaultValue; + } + + public void setDefaultValue(Object defaultValue) { + this.defaultValue = defaultValue; + } + + public String getShield() { + return shield; + } + + public void setShield(String shield) { + this.shield = shield; + } + + public boolean isVisible() { + return visible; + } + + public void setVisible(boolean visible) { + this.visible = visible; + } + + public boolean isSortable() { + return sortable; + } + + public void setSortable(boolean sortable) { + this.sortable = sortable; + } + + public boolean isReadonly() { + return readonly; + } + + public void setReadonly(boolean readonly) { + this.readonly = readonly; + } + + public boolean isFilterable() { + return filterable; + } + + public void setFilterable(boolean filterable) { + this.filterable = filterable; + } + + public List getAlias() { + return alias; + } + + public void setAlias(List alias) { + this.alias = alias; + } + + public String getxComment() { + return xComment; + } + + public void setxComment(String xComment) { + this.xComment = xComment; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + VerbParameter that = (VerbParameter) o; + return mandatory == that.mandatory && + multiple == that.multiple && + visible == that.visible && + sortable == that.sortable && + readonly == that.readonly && + filterable == that.filterable && + Objects.equals(name, that.name) && + Objects.equals(type, that.type) && + Objects.equals(options, that.options) && + Objects.equals(min, that.min) && + Objects.equals(max, that.max) && + Objects.equals(defaultValue, that.defaultValue) && + Objects.equals(shield, that.shield) && + Objects.equals(alias, that.alias) && + Objects.equals(xComment, that.xComment); + } + + @Override + public int hashCode() { + + return Objects.hash(name, type, options, mandatory, min, max, multiple, defaultValue, shield, visible, sortable, readonly, filterable, alias, xComment); + } }