Spring RestTemplate с Jaxb2RootElementHttpMessageConverter не может распознавать аннотации JAXB - PullRequest
0 голосов
/ 06 мая 2020

Я потратил много времени на отладку этой проблемы, но не смог найти решения. Итак, я использовал обходной путь, но я хочу поделиться проблемой, чтобы помочь кому-то в такой же ситуации.

Вкратце, приложение представляет собой плагин TeamCity, который взаимодействует с репозиторием nexus.

pom. xml:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <parent>
    <artifactId>some-plugin</artifactId>
    <groupId>com.something</groupId>
    <version>1.0-SNAPSHOT</version>
  </parent>
  <artifactId>some-plugin-server</artifactId>
  <packaging>jar</packaging>

  <properties>
    <jaxb.version>2.3.0</jaxb.version>
  </properties>

  <dependencies>

    <dependency>
      <groupId>ch.qos.logback</groupId>
      <artifactId>logback-classic</artifactId>
      <version>1.1.7</version>
    </dependency>

    <dependency>
      <groupId>javax.xml.bind</groupId>
      <artifactId>jaxb-api</artifactId>
      <version>${jaxb.version}</version>
    </dependency>

   <dependency>
      <groupId>com.sun.xml.bind</groupId>
      <artifactId>jaxb-impl</artifactId>
      <version>${jaxb.version}</version>
   </dependency>


    <dependency>
      <groupId>org.jetbrains.teamcity</groupId>
      <artifactId>server-api</artifactId>
      <version>${teamcity-version}</version>
      <scope>provided</scope>
    </dependency>

    <dependency>
      <groupId>org.jetbrains.teamcity</groupId>
      <artifactId>server-web-api</artifactId>
      <version>${teamcity-version}</version>
      <type>war</type>
      <scope>provided</scope>
    </dependency>

    <dependency>
      <groupId>org.jetbrains.teamcity</groupId>
      <artifactId>tests-support</artifactId>
      <version>${teamcity-version}</version>
      <scope>test</scope>
    </dependency>
  </dependencies>

  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>
          <source>1.8</source>
          <target>1.8</target>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>

Есть упомянутый родитель, но он не содержит ничего, кроме репозиториев и настроек pluginRepositories.

Аннотации над моими java классами:

@XmlRootElement(name = "versioning")
@XmlAccessorType(XmlAccessType.FIELD)
public class Versioning implements Serializable {

    private static final long serialVersionUID = 2L;

    private String latest;
    private String release;

    @XmlElementWrapper(name="versions")
    @XmlElement(name = "version")
    private List<String> versions;

    public String getLatest() {
        return latest;
    }

    public void setLatest(String latest) {
        this.latest = latest;
    }

    public String getRelease() {
        return release;
    }

    public void setRelease(String release) {
        this.release = release;
    }

    public List<String> getVersions() {
        return versions;
    }

    public void setVersions(List<String> versions) {
        this.versions = versions;
    }
}

@XmlRootElement(name = "metadata")
@XmlAccessorType(XmlAccessType.FIELD)
public class MetaData implements Serializable {

    private static final long serialVersionUID = 1L;

    @XmlElement(name = "versioning")
    private Versioning versioning;

    public Versioning getVersioning() {
        return versioning;
    }

    public void setVersioning(Versioning versioning) {
        this.versioning = versioning;
    }
}

Классы представляют метаданные. xml из нексуса. Из pom. xml нет ясности, что зависимости teamcity добавляют Spring 4 в мой проект:

enter image description here

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

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"
       default-autowire="constructor">

    <bean id="versionService" class="com.aliter.teamcity.service.impl.VersionServiceImpl" autowire="byName"/>

    <bean id="appController" class="com.aliter.teamcity.AppController"/>

    <bean id="restTemplate" class="org.springframework.web.client.RestTemplate"/>

</beans>

В классе VersionServiceImpl.class есть метод, отправляющий запрос в нексус:

    private MetaData getMetaData(String url) {

        HttpEntity<String> request = new HttpEntity<>(getAuthorization());
        try {
            ResponseEntity<MetaData> metaDataResponseEntity = restTemplate.exchange(url, HttpMethod.GET, request, MetaData.class);
            return metaDataResponseEntity.getBody();
        } catch (RestClientException e) {
            LOGGER.error("Metadata xml cannot be obtained.", e);
            return null;
        }
    }

    private HttpHeaders getAuthorization() {

        String plainCreds = "username:password";
        byte[] plainCredsBytes = plainCreds.getBytes();
        byte[] base64CredsBytes = Base64.encodeBase64(plainCredsBytes);
        String base64Creds = new String(base64CredsBytes);

        HttpHeaders headers = new HttpHeaders();
        headers.setAccept(Arrays.asList(MediaType.APPLICATION_XML, MediaType.TEXT_XML, MediaType.APPLICATION_XHTML_XML, MediaType.TEXT_HTML));
        headers.add("Authorization", "Basic " + base64Creds);
        return headers;
    }

Я получил исключение: RestClientException: не удалось извлечь ответ: не найдено подходящего HttpMessageConverter для типа ответа [ class com.aliter.teamcity.model.MetaData] и тип содержимого [application / xml]

RestTemplate явно следующим образом: private stati c final boolean jaxb2Present = ClassUtils.isPresent (" javax. xml .bind.Binder ", RestTemplate.class.getClassLoader ()); регистрирует Jaxb2RootElementHttpMessageConverter, именно там я это проверил. Я выполнил отладку и остановился, когда обработчик ответов Spring Http пытается распознать через Jaxb2RootElementHttpMessageConverter JAXB-аннотации над моими классами и из метода:

    @Override
    public boolean canRead(Class<?> clazz, MediaType mediaType) {
        return (clazz.isAnnotationPresent(XmlRootElement.class) || clazz.isAnnotationPresent(XmlType.class)) &&
                canRead(mediaType);
    }

Он возвращает, что аннотации отсутствуют над классами, но они даже есть. Я использовал JDK 8.

...