Как добавить дополнительный элемент в WADL?

Я пытаюсь добавить объект ошибки в ответ (с статусом HTTP 422). Он отлично работает, но я также хочу добавить схему моего объекта ошибки в автоматически сгенерированный WADL.

Код:

Классы моделей JAX-B:

@XmlRootElement(namespace = "http://www.test.com/test")
@XmlAccessorType(value = XmlAccessType.FIELD)
public class UnprocessableEntityError {

    @XmlElement
    private String key;

    public String getKey() {
        return key;
    }

    public void setKey(final String key) {
        this.key = key;
    }
}

@XmlRootElement(namespace = "http://www.test.com/")
public class TestModel {
}

Класс ресурсов JAX-RS:

@Path("test")
public class TestResource {

    @POST
    public TestModel doSomething() {
        throw new WebApplicationException("Error", Response.status(422).entity(new UnprocessableEntityError()).build());
    }
}

Конфигурация CXF:

<jaxrs:server address="/rest" id="test" staticSubresourceResolution="true">
    <jaxrs:serviceBeans>
        <ref bean="testResource" /> 
    </jaxrs:serviceBeans>
    <jaxrs:providers>
        <bean class="org.apache.cxf.jaxrs.provider.JAXBElementProvider" />
        <bean class="com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider" />
    </jaxrs:providers>
</jaxrs:server>

ВАДЛ:

<?xml version="1.0"?>
<application xmlns:prefix1="http://www.test.com/" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns="http://wadl.dev.java.net/2009/02">
    <grammars>
        <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns="http://www.test.com/" targetNamespace="http://www.test.com/" elementFormDefault="unqualified" attributeFormDefault="unqualified">
            <xs:complexType name="testModel">
                <xs:sequence/>
            </xs:complexType>
        </xs:schema>
        <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns="http://www.test.com/" targetNamespace="http://www.test.com/" elementFormDefault="unqualified" attributeFormDefault="unqualified">
            <xs:import/>
            <xs:element name="testModel" type="testModel"/>
        </xs:schema>
    </grammars>
    <resources base="http://localhost:8080/test-app/services/rest/1">
        <resource path="/test">
            <method name="POST">
                <response>
                    <representation mediaType="*/*" element="prefix1:testModel"/>
                </response>
            </method>
        </resource>
    </resources>
</application>

Есть ли способ добавить (только для документации) дополнительный элемент в грамматику автоматически сгенерированного WADL?


person dur    schedule 26.05.2016    source источник
comment
Включить XSD с определением будет для вас действительным? ‹wadl:grammars›‹wadl:include href=test.xsd/›‹/wadl:grammars› (со ссылкой на внешнее xsd или встроенное определение)   -  person pedrofb    schedule 07.06.2016
comment
@pedrofb: Как я могу включить XSD? Есть ли какое-либо свойство аннотации или конфигурации?   -  person dur    schedule 07.06.2016


Ответы (1)


Вы можете настроить автоматическую генерацию WADL, но это не очень гибко. Общая документация по CXF находится здесь, но она бесполезна.

В области <grammars> вы можете включить собственный XSD или связать его

Определите WadlGenerator в файле весны CXF и включите в провайдер jaxrs. Например, с books.xsd

<jaxrs:server address="/rest" id="test" >
    <jaxrs:providers>
        <ref bean="wadlGenerator" />
    </jaxrs:providers>
</jaxrs:server>

<bean id="wadlGenerator" class="org.apache.cxf.jaxrs.model.wadl.WadlGenerator">
    <property name="schemaLocations" value="classpath:/books.xsd"/>
</bean>

Программно тоже можно

WadlGenerator wg = new WadlGenerator();
wg.setSchemaLocations(Collections.singletonList("classpath:/books.xsd"));

Сгенерированный WADL будет таким

<application xmlns="http://wadl.dev.java.net/2009/02" xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <grammars>
       <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://superbooks" attributeFormDefault="unqualified" elementFormDefault="unqualified" targetNamespace="http://superbooks">
         <xs:element name="thebook" type="tns:book"/>
         <xs:complexType name="book">
            <xs:sequence>
                <xs:element minOccurs="0" name="chapter" type="xs:string"/>
                <xs:element name="id" type="xs:int"/>
            </xs:sequence>
         </xs:complexType>
      </xs:schema>
</grammars>

Кроме того, вы можете добавить ссылку

<bean id="wadlGenerator" class="org.apache.cxf.jaxrs.model.wadl.WadlGenerator">
    <property name="externalLinks" value="http://books"/> 
</bean>

ВАДЛ

<grammars>
    <include href="http://books"/>
</grammars>

Полная документация по WadlGenerator . Я тестировал с CXF 2.7

ОТРЕДАКТИРОВАНО

Пользовательский генератор WADL

CXF WadlGenerator заполняет раздел «грамматики» XSD, внешними ссылками или автоматически сгенерированным wadl, но не позволяет их комбинировать. Чтобы добавить ссылку на внешний ресурс к сгенерированной грамматике, необходимо создать собственный WadlGenerator.

<grammars>
    <include href="http://books"/>
    <!-- The autogenerated grammar-->
</grammars>

Это полностью функциональный класс для CXF 2.7, но я надеюсь, что он будет работать и в любой более поздней версии, поскольку использует наследование и переписывает лишь минимальную часть кода. Он объединяет externalLinks (если существует) с автоматически сгенерированным кодом или XSD.

package com.wadl;

import java.net.URI;
import java.util.LinkedList;
import java.util.List;
import java.util.logging.Logger;

import javax.ws.rs.core.UriInfo;
import javax.xml.bind.JAXBContext;

import org.apache.cxf.common.logging.LogUtils;
import org.apache.cxf.jaxrs.model.ResourceTypes;
import org.apache.cxf.jaxrs.model.wadl.WadlGenerator;

public class CustomWadlGenerator extends WadlGenerator {
    private List<URI> externalSchemaLinks;
    private static final Logger LOG = LogUtils.getL7dLogger(CustomWadlGenerator.class);

    //Overwrite setExternalLink so that it is not used in the superclass
    @Override
    public void setExternalLinks(List<String> externalLinks) {
        externalSchemaLinks = new LinkedList<URI>();
        for (String s : externalLinks) {
            try {
                String href = s;
                if (href.startsWith("classpath:")) {
                    int index = href.lastIndexOf('/');
                    href = index == -1 ? href.substring(9) : href.substring(index + 1);

                }
                externalSchemaLinks.add(URI.create(href));
            } catch (Exception ex) {
                LOG.warning("Not a valid URI : " + s);
                externalSchemaLinks = null;
                break;
            }
        }
    }


    private class ExternalSchemaWriter implements WadlGenerator.SchemaWriter {

        private List<URI>links;
        private UriInfo uriInfo;
        private SchemaWriter writer;

        public ExternalSchemaWriter(List<URI>links, UriInfo ui, SchemaWriter writer){
            this.links = links;
            this.uriInfo = ui;
            this.writer = writer;
        }
        public void write(StringBuilder sb) {
            //write links
            for (URI link : links) {
                try {
                    URI value = link.isAbsolute() ? link : uriInfo.getBaseUriBuilder().path(link.toString()).build(new Object[0]);

                    sb.append("<include href=\"").append(value.toString()).append("\"/>");
                } catch (Exception ex) {
                     CustomWadlGenerator.LOG.warning("WADL grammar section will be incomplete, this link is not a valid URI : " + link.toString());
                }
            }

           //concat with default writer
            writer.write(sb);
        }
    }   

    @Override
    protected SchemaWriter createSchemaWriter(ResourceTypes resourceTypes, JAXBContext context, UriInfo ui)  {
        SchemaWriter schemaCollectionWriter = super.createSchemaWriter(resourceTypes, context, ui);

        if (externalSchemaLinks == null){
            //default behaviour
            return schemaCollectionWriter;
        } else {
            //use custom writer
            return new ExternalSchemaWriter(externalSchemaLinks,ui,schemaCollectionWriter);
        }
    }
}

Установите WadlGenerator в весенней конфигурации

<bean id="wadlGenerator" class="com.wadl.CustomWadlGenerator">
    <property name="externalLinks" value="http://books"/> 
</bean>
person pedrofb    schedule 07.06.2016
comment
К сожалению, свойство externalLinks не работает так, как мне нужно. CXF добавляет ссылку, но удаляет все остальные элементы из существующей сгенерированной схемы. - person dur; 07.06.2016
comment
Та же проблема со свойством schemaLocations, CXF заменяет грамматику новым XSD вместо добавления нового XSD к сгенерированной грамматике. - person dur; 07.06.2016
comment
Такое решение приемлемо?<grammars> <include href="http://books"/> <!-- Here the autogenerated code for other services--> </grammars> Спецификация это допускает. WadlGenerator не поддерживают это, но код кажется простым для обновления. Если вам подходит, могу попробовать - person pedrofb; 07.06.2016
comment
WadlGenerator.createSchemaWriter защищен, поэтому его можно переписать в подклассе, чтобы объединить ExternalSchemaWriter и модуль записи по умолчанию. - person pedrofb; 08.06.2016