java - restful - Incluir valores posibles de @PathParam en WADL
restful java (2)
Estamos utilizando Jersey para la implementación de API RESTful utilizando su genial característica de generación WADL automática.
Solo como un ejemplo tenemos un método
@GET
@Path("/{id}/{attribute}")
@Produces(MediaType.APPLICATION_JSON)
public Object getAttributeByID(@PathParam("id") long id, @PathParam("attribute") String attribute) {
....
}
Esto genera el siguiente fragmento en WADL:
<param type="xs:string" style="template" name="attribute:.*"/>
El atributo puede ser name
, type
, size
y no solo queremos validar el valor en tiempo de ejecución sino también mostrarlo en wadl generado. De acuerdo con este documento, dicha característica debe ser respaldada generando varias etiquetas <option>
dentro de <param>
, es decir, yo soy esperando algo como lo siguiente:
<param type="aws:Attributes" style="template" name="attribute">
<option value="name"/>
<option value="type"/>
<option value="size"/>
</param>
Mi problema es habilitarlo con Jersey. Si no pude encontrar el documento relevante y asumí que probablemente si cambio el tipo de parámetro de String
a enum
esta característica funcionará automáticamente, así que cambié la firma del método a:
@Path("/{id}/{attribute}")
@Produces(MediaType.APPLICATION_JSON)
public Object getAttributeByID(@PathParam("id") long id, @PathParam("attribute") Attribute attribute) {
....
}
dónde
public enum Attribute {
name, type, size
}
pero Jersey todavía genera la etiqueta <param>
sin opciones y el tipo de parámetro sigue siendo xs:string
.
Intenté encontrarlo en el código de Jersey y encontré la clase com.sun.research.ws.wadl.Option
con anotaciones JAXB relevantes, por lo que parece ser relevante, pero no sé cómo hacerlo funcionar. Supongo que el problema está en WadlGeneratorConfig
.
Aquí hay una parte relevante de la definición de Jersey en nuestro web.xml
<filter>
<filter-name>REST-API</filter-name>
<filter-class>com.sun.jersey.spi.container.servlet.ServletContainer</filter-class>
................
<init-param>
<param-name>com.sun.jersey.config.property.WadlGeneratorConfig</param-name>
<param-value>com.mycompany.resource.OurWADLGenerator</param-value>
</init-param>
<init-param>
<param-name>com.sun.jersey.config.property.packages</param-name>
<param-value>com.mycompany</param-value>
</init-param>
</filter>
donde OurWADLGenerator
código de OurWADLGenerator
es:
public class OurWADLGenerator extends WadlGeneratorConfig {
@Override
public List<WadlGeneratorDescription> configure() {
return generator(WadlGeneratorApplicationDoc.class)
.prop("applicationDocsStream", "application-doc.xml")
.generator(WadlGeneratorResourceDocSupport.class)
.prop("resourceDocStream", "resourcedoc.xml").descriptions();
}
}
¿Que me estoy perdiendo aqui? Gracias por adelantado.
Después de algunas investigaciones, no encontré ningún código en jersey donde se rellena la lista de opciones. (Probablemente algo que aún no es compatible )
Entonces puede implementar su propio WadlGenerator e insertarlo en la cadena del generador.
Aquí hay un ejemplo de OptionsWadlGenerator
agregando los elementos <option>
para el parámetro de tipo Enum
package com.mycompany;
import com.sun.jersey.api.model.AbstractMethod;
import com.sun.jersey.api.model.AbstractResource;
import com.sun.jersey.api.model.AbstractResourceMethod;
import com.sun.jersey.api.model.Parameter;
import com.sun.jersey.server.wadl.WadlGenerator;
import com.sun.research.ws.wadl.Application;
import com.sun.research.ws.wadl.Method;
import com.sun.research.ws.wadl.ObjectFactory;
import com.sun.research.ws.wadl.Option;
import com.sun.research.ws.wadl.Param;
import com.sun.research.ws.wadl.RepresentationType;
import com.sun.research.ws.wadl.Request;
import com.sun.research.ws.wadl.Resource;
import com.sun.research.ws.wadl.Resources;
import com.sun.research.ws.wadl.Response;
import javax.ws.rs.core.MediaType;
public class OptionsWadlGenerator implements WadlGenerator {
private WadlGenerator _delegate;
private ObjectFactory objectFactory = new ObjectFactory();
@Override
public Param createParam(AbstractResource r, AbstractMethod m, Parameter p) {
Param param = _delegate.createParam(r, m, p);
if(((Parameter)p).getParameterClass().isEnum()){
Object[] values = p.getParameterClass().getEnumConstants();
for(Object enumItem:values){
Option option = objectFactory.createOption();
option.setValue(((Enum)enumItem).name());
param.getOption().add(option);
}
}
return param;
}
@Override
public void setWadlGeneratorDelegate(WadlGenerator delegate) {
this._delegate = delegate;
}
@Override
public Application createApplication() {
return _delegate.createApplication();
}
... all other methods also simply call the _delegate equivalent method
}
Y, por supuesto, para insertarlo en su cadena, haga algo como eso:
public class OurWADLGenerator extends WadlGeneratorConfig {
@Override
public List<WadlGeneratorDescription> configure() {
return generator(WadlGeneratorApplicationDoc.class)
.prop("applicationDocsStream", "application-doc.xml")
.generator(WadlGeneratorResourceDocSupport.class)
.prop("resourceDocStream", "resourcedoc.xml")
.generator(OptionsWadlGenerator.class).descriptions();
}
}
Una búsqueda rápida de los usos de com.sun.research.ws.wadl.Param.getOption()
(ver resultados aquí ) muestra que en realidad nunca se invoca desde la biblioteca. Supongo que solo está allí porque estas clases son generadas por xjc desde wadl.xsd. Sin embargo, parece que Jersey básicamente ignora esta información en archivos wadl, y de manera similar no le importa incluirla en los archivos wadl que genera.
Hace un par de años terminamos escribiendo nuestro propio código para generar wadl, porque las herramientas disponibles eran muy malas. Esto podría haber cambiado desde entonces, pero el problema anterior muestra que el soporte adecuado para wadl todavía no está allí. :(