@XmlPath не влияет на маршалинг JAXB

Я пытаюсь создать XML, используя подход JaxB Marshalling. Я хочу пропустить родительский тег для определенных дочерних элементов или могу добавить новый родительский тег XML для определенного элемента. Следовательно, я пытаюсь использовать @XmlPath от import org.eclipse.persistence.oxm.annotations.XmlPath;.

Я слежу за блогом основателя (блог на @XmlPath), чтобы заставить его работать, но по какой-то причине @XmlPath не влияет, и выходной XML не совпадает с тем, что показано в блоге. Я следил за всем процессом, упомянутым в блоге, а также упоминал здесь в различных ответах.

Все мои классы входят в пакет model.jaxb. Кроме того, я создал файл jaxb.properties в этом пакете.

Ниже приведен мой Customer класс:

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.eclipse.persistence.oxm.annotations.XmlPath;

@Getter
@Setter
@NoArgsConstructor
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Customer {

  @XmlPath("contact-info/billing-address")
  private Address billingAddress;

  @XmlPath("contact-info/shipping-address")
  private Address shippingAddress;

}

Ниже приведен мой Address класс:

@Getter
@Setter
@NoArgsConstructor
public class Address {

  private String street;

}

Ниже приводится класс Demo:

public class Demo {

  public static void main(String[] args) throws Exception {
    JAXBContext jc = JAXBContext.newInstance(Customer.class);

    Customer customer = new Customer();

    Address billingAddress = new Address();
    billingAddress.setStreet("1 Billing Street");
    customer.setBillingAddress(billingAddress);

    Address shippingAddress = new Address();
    shippingAddress.setStreet("2 Shipping Road");
    customer.setShippingAddress(shippingAddress);

    Marshaller m = jc.createMarshaller();
    m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
    m.marshal(customer, System.out);
  }

}

XML, который я получаю с @XmlPath и без него, на самом деле одно и то же. Похоже, что @XmlPath не влияет на сортировку.

<customer>
    <billingAddress>
        <street>1 Billing Street</street>
    </billingAddress>
    <shippingAddress>
        <street>2 Shipping Road</street>
    </shippingAddress>
</customer>

Я создал jaxb.properties файл в моем package model.jaxb с содержанием:

javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory

Согласно блогу выходной XML должен быть примерно таким:

<customer>
   <contact-info>
      <billing-address>
         <street>1 Billing Street</street>
      </billing-address>
      <shipping-address>
         <street>2 Shipping Road</street>
      </shipping-address>
   </contact-info>
<customer>

Я не уверен, что делаю неправильно, из-за чего не могу получить XML, как ожидал. Я много чего пробовал, но ни один из них не работал, поэтому разместил здесь то же самое.

Может ли кто-нибудь помочь мне с тем, как я могу сделать @XmlPath пинок во время маршаллинга, чтобы я мог получить ожидаемый тег во время маршаллинга?

**** РЕДАКТИРОВАТЬ *****

Я использую версию Java 15.0.01 согласно Intellij IDE File -> Project Structure. Я видел один ответ, в котором упоминалось, что Moxy не работает непосредственно выше Java 11 Ответ Java 11.0 выше.

Итак, я сделал следующее:

  1. Я добавил зависимость и build, как указано в ответе выше, поэтому мой 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/xsd/maven-4.0.0.xsd">
    
      <modelVersion>4.0.0</modelVersion>
          <groupId>model.jaxb</groupId>
        <version>1.0-SNAPSHOT</version>
    
      <artifactId>model-jaxb</artifactId>
    
      <build>
        <plugins>
          <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <configuration>
              <source>8</source>
              <target>8</target>
            </configuration>
          </plugin>
        </plugins>
        <resources>
          <resource>
            <directory>src/main/java</directory>
            <excludes>
              <exclude>**/*.java</exclude>
            </excludes>
          </resource>
        </resources>
      </build>
    
      <dependencies>
    
        <dependency>
          <groupId>org.projectlombok</groupId>
          <artifactId>lombok</artifactId>
          <version>1.18.16</version>
          <scope>provided</scope>
        </dependency>
    
        <dependency>
          <groupId>com.sun.activation</groupId>
          <artifactId>javax.activation</artifactId>
          <version>1.2.0</version>
        </dependency>
    
        <dependency>
          <groupId>javax.xml.bind</groupId>
          <artifactId>jaxb-api</artifactId>
          <version>2.3.1</version>
        </dependency>
    
        <dependency>
          <groupId>com.sun.xml.bind</groupId>
          <artifactId>jaxb-core</artifactId>
          <version>2.3.0.1</version>
        </dependency>
    
        <dependency>
          <groupId>com.sun.xml.bind</groupId>
          <artifactId>jaxb-impl</artifactId>
          <version>2.3.1</version>
        </dependency>
    
        <dependency>
          <groupId>org.eclipse.persistence</groupId>
          <artifactId>eclipselink</artifactId>
          <version>2.7.6</version>
        </dependency>

    <dependency>
      <groupId>jakarta.xml.bind</groupId>
      <artifactId>jakarta.xml.bind-api</artifactId>
      <version>2.3.2</version>
    </dependency>

    <dependency>
      <groupId>org.glassfish.jaxb</groupId>
      <artifactId>jaxb-runtime</artifactId>
      <version>2.3.2</version>
    </dependency>
        
      </dependencies>
    
    </project>

Когда я запускаю программу, я получаю сообщение об ошибке: Exception in thread "main" java.lang.NoClassDefFoundError: jakarta/xml/bind/JAXBException

Caused by: java.lang.ClassNotFoundException: jakarta.xml.bind.JAXBException

Я пробовал много вещей, упомянутых в StackOverflow for this error and most of the answers mentioned adding the dependency` Я добавил все зависимости, упомянутые в ответе. Я не уверен, что не так.

Может ли кто-нибудь помочь мне решить эту проблему?


person BATMAN_2008    schedule 12.05.2021    source источник
comment
Есть ли в вашем pom.xml файле этап сборки, который обеспечивает включение jaxb.properties файла в JAR (или WAR), созданный Maven?   -  person andrewjames    schedule 12.05.2021
comment
Я добавил примечание о необходимом этапе сборки Maven к своему ответу в этом другом вопросе, если это поможет. Кроме того, я не могу воссоздать вашу проблему. Ваш код генерирует ожидаемый XML, когда я использую его с этим дополнительным шагом сборки (но не без!).   -  person andrewjames    schedule 12.05.2021
comment
Большое спасибо за проверку и за ответ. Я немного смог разобраться в проблеме. Я добавил свой jaxb.properties файл в папку resources->model->jaxb той же структуры, что и мой domain classes which will be used by jaxb, после этого я добавил зависимость, упомянутую в вашем ответе, и еще две зависимости, такие как org.glassfish.jaxb и jakarta.xml.bind. Теперь он выдает мне ошибку Exception in thread "main" java.lang.NoClassDefFoundError: jakarta/xml/bind/JAXBContext   -  person BATMAN_2008    schedule 12.05.2021
comment
Хорошо, но если вы вернетесь к зависимостям в моем другом ответе и добавите шаг , касающийся сборки Maven, тогда он сработает для вас (потому что ваш код работает для меня). Затем вы можете начать настраивать зависимости, если вам нужно, но вы будете делать это из конфигурации, которая работает.   -  person andrewjames    schedule 12.05.2021
comment
Спасибо за ответ и за то, что нашли время. Я действительно выполнил шаги, упомянутые в вашем ответе и многих других ресурсах, и внес соответствующие изменения, но все же вижу эту Exception in thread "main" java.lang.NoClassDefFo undError: jakarta/xml/bind/JAXBContext проблему. Я изменил вопрос на основании этой проблемы. Не могли бы вы взглянуть на раздел edited в этом вопросе и высказать свое мнение?   -  person BATMAN_2008    schedule 12.05.2021
comment
Что касается ваших заметок, я добавил файл jaxb.properties в свою папку ресурсов: ваш файл свойств не следует помещать в папку resources. Он должен находиться в том же месте, что и ваши исходные файлы Java, а именно в пакете model.jaxb. Создание копии этой структуры каталогов в resources - совсем другое дело. Ваша команда Maven build гарантирует, что файл свойств будет скопирован в то же целевое расположение, что и ваши скомпилированные class файлы. Вы можете открыть файл JAR, чтобы убедиться, что он оказался в нужном месте.   -  person andrewjames    schedule 12.05.2021
comment
@andrewjames На самом деле я поместил оба места в папку Java Classes и папку resources, просто чтобы посмотреть, будет ли это иметь значение. Теперь после вашего комментария я удалил файл из папки Resources. Так что теперь он просто присутствует в том же пакете, что и мой java classes. Это предоставляет мне XML, но XML не принимает во внимание элементы @XmlPath. С @XmlPath или без него он производит тот же XML, поэтому я не уверен, что здесь не так. Потому что вы использовали тот же код, и он работает для вас, но по какой-то причине он не работает для меня. Что я могу попробовать?   -  person BATMAN_2008    schedule 12.05.2021
comment
Единственное, что я вижу, отличается между вашим кодом и моим - это использование Lombok (я его не использую). Это не должно иметь никакого значения ...   -  person andrewjames    schedule 12.05.2021
comment
На самом деле ошибка все еще существует после удаления файла jaxb.properties из папки resources. В большинстве ответов упоминается, что ошибка связана с отсутствием dependency. Я добавил все необходимые зависимости, но все равно получаю сообщение об ошибке: Exception in thread "main" java.lang.NoClassDefFoundError: jakarta/xml/bind/JAXBException   -  person BATMAN_2008    schedule 12.05.2021
comment
Почему у вас jakarta.xml.bind в зависимостях?   -  person andrewjames    schedule 12.05.2021
comment
Это то, что упоминалось в большинстве ответов по этой проблеме, поэтому я тоже пробовал: jakarta.xml.bind и org.glassfish.jaxb. Для Java 11 и выше они говорят, что нам нужно использовать эту зависимость. Если я удалю это, я также получаю ошибки. Если я добавлю, то тоже получаю ошибки. Я очень не понимаю, что нужно делать. Удалить оба или только один jakarta.xml.bind? Вот ссылка на то, что я имел в виду: stackoverflow.com/a/43574427/7584240   -  person BATMAN_2008    schedule 12.05.2021
comment
Удалите все ваши зависимости. Затем добавьте обратно только эти два: <dependency><groupId>javax.xml.bind</groupId><artifactId>jaxb-api</artifactId><version>2.3.1</version></dependency> и <dependency><groupId>org.eclipse.persistence</groupId><artifactId>eclipselink</artifactId><version>2.7.6</version></dependency>. Расскажи мне, что происходит.   -  person andrewjames    schedule 12.05.2021
comment
Конечно, поэтому я удалил все свои зависимости и добавил только 3 зависимости, которые вы предоставили (и Lombok), и запустил Demo.class, который имеет JaxBContent. Я получаю следующую ошибку: Exception in thread "main" java.lang.NoClassDefFoundError: jakarta/xml/bind/JAXBException после нескольких строк ошибки у меня тоже есть эта строка Caused by: java.lang.ClassNotFoundException: jakarta.xml.bind.JAXBException   -  person BATMAN_2008    schedule 12.05.2021
comment
Это должно работать для более старой версии MOXy (v2.7). Затем, чтобы перейти на последнюю и лучшую версию MOXy, см. Мои последние обновления на этот ответ. Смотрите новый раздел ОБНОВЛЕНИЯ для MOXy версии 3.   -  person andrewjames    schedule 12.05.2021
comment
В своем комментарии я указал только 2 зависимости, а не 3. Извините, но я не знаю, какие изменения вы вносите - они не соответствуют моим комментариям. Во всяком случае, смотрите мои заметки о последних и лучших.   -  person andrewjames    schedule 12.05.2021
comment
Привет, мне очень жаль, что я добавил только эти 2 зависимости, включая Lombok 3, я имел в виду, что действительно сожалею об ошибке. На самом деле, я не вношу никаких изменений, кроме того, что вы меня просили. Теперь я пытаюсь реализовать на основе вашего обновленного ответа из вашего сообщения.   -  person BATMAN_2008    schedule 12.05.2021
comment
Хорошо, желаю удачи!   -  person andrewjames    schedule 12.05.2021
comment
Попробовал обновленный код из вашего поста. 1. Я обновил содержимое файла jaxb.properties до jakarta (заменил старую строку на новую). 2. Добавлены новые зависимости в pom.xml с версией 3.0.0 (удалены старые и сохранены новые зависимости). 3. Изменил импорт в Demo.class на jakarta с jaxb. когда я бегу, я получаю следующую ошибку: Exception in thread "main" javax.xml.bind.JAXBException: jaxb.properties in package (link to package) does not contain the javax.xml.bind.JAXBContextFactory property.   -  person BATMAN_2008    schedule 12.05.2021
comment
Я рекомендую начать с нуля с совершенно нового Java-проекта. Я думаю, что вы пытались внести так много изменений, что что-то серьезно не в порядке в вашем коде / конфигурации. Эти ошибки в принципе невозможны, учитывая зависимости, которые вы должны использовать. (Кроме того, убедитесь, что вы выполняете полную очистку и сборку после каждого внесенного изменения.) И попробуйте для начала без Lombok. Добавьте его обратно, когда у вас будет что-то, что действительно работает.   -  person andrewjames    schedule 12.05.2021
comment
Конечно, я буду следовать вашим инструкциям и создавать с нуля. Разместите мои наблюдения здесь после попытки. Еще раз спасибо за терпение и руководство.   -  person BATMAN_2008    schedule 12.05.2021
comment
Привет, да, наконец, это сработало. Мне не хватало одной мелочи, мой Customer.class все еще использовал imports из jaxb вместо Jakarta. Я снова все это анализировал, нашел это. Я изменил весь импорт на Jakarta, и все заработало, и я смог получить XML, как я ожидал. Кроме того, @XmlPath работает должным образом.   -  person BATMAN_2008    schedule 12.05.2021
comment
Большое спасибо за терпение и за помощь в устранении этой ошибки. У меня ушел целый день, чтобы понять и исправить. Наконец, в конце концов, я смог его получить. Спасибо вам :) Если возможно, предоставьте ответ из своего сообщения здесь и, возможно, еще несколько баллов, чтобы люди могли быстро находить ответы и не тратить так много времени. Я приму ответ, и вы получите вознаграждение за свои усилия.   -  person BATMAN_2008    schedule 12.05.2021
comment
Рад, что ты решил это! Отлично! Приглашаем вас ответить на свой вопрос здесь, чтобы описать, как вы решили свою проблему - ваша собственная точка зрения будет полезна. Если вы хотите (и это, конечно, на 100% необязательно), вы также можете проголосовать за другой ответ здесь .   -  person andrewjames    schedule 12.05.2021
comment
@andrewjames У меня есть одно небольшое сомнение. Теперь все работает нормально, и мой адрес можно получить в формате XML следующим образом: `‹billing-address› ‹street› 1 Billing Street ‹/street› ‹/billing-address› . Now what if I want to skip the ‹street›` тег с помощью тега @XmlPath? Я попытался добавить следующие @XmlPath(".") и @XmlPath("./text()"), но оба выдают ошибку. Я хочу добавить значение street непосредственно к <billing-address>, чтобы можно было пропустить тег <street>. Я планировал использовать @XmlPath именно по этой основной причине. Можно ли использовать @XmlPath? Спасибо   -  person BATMAN_2008    schedule 13.05.2021
comment
@andrewjames Неважно. Я понял. Я только что добавил @XmlAccessorType(XmlAccessType.FIELD) в свой Address.class, и это сработало, поэтому теперь тег street напрямую сопоставлен с тегом customer, а billing-address был пропущен.   -  person BATMAN_2008    schedule 13.05.2021


Ответы (1)


Наконец-то удалось найти решение с большой помощью @andrewjames. Публикуем решение для того же самого, чтобы кто-то мог быстро найти решение и не проводить целый день, как я :)

Вы также можете выполнить шаги, упомянутые @andrewjames в его ответе < / а>.

  1. Убедитесь, что у вас есть только ОДНА копия файла jaxb.properties в том же пакете, что и у класса домена (та, которая будет использоваться во время сортировки в данном случае Customer.class). Содержимое файла должно быть:

    jakarta.xml.bind.context.factory = org.eclipse.persistence.jaxb.JAXBContextFactory

2. Удалите все зависимости из вашего pom.xml файла и просто добавьте следующие 2 зависимости:

<dependency>
    <groupId>jakarta.xml.bind</groupId>
    <artifactId>jakarta.xml.bind-api</artifactId>
    <version>3.0.1</version>
</dependency>

<dependency>
    <groupId>org.eclipse.persistence</groupId>
    <artifactId>eclipselink</artifactId>
    <version>3.0.0</version>
</dependency>
  1. Убедитесь, что все ваши классы (в данном случае Customer.class и Demo.ckass) используют импорт из import jakarta.xml.bind.JAXBContext;.

Раньше брал от import javax.xml.bind.JAXBContext;, надо было заменить от import jakarta.xml.bind.JAXBContext;.

Я вносил изменения в Demo.class и забыл изменить Customer.class, поэтому возникла проблема defclass. Поэтому убедитесь, что весь ваш класс использует импорт из Jakarta, а не из Javax.

  1. Добавьте в свой pom.xml следующий <build>:
      <build>
        <resources>
          <resource>
            <directory>src/main/java</directory>
            <excludes>
              <exclude>**/*.java</exclude>
            </excludes>
          </resource>
        </resources>
      </build>
  1. После внесения этих изменений запустите Demo.class, это должно дать вам ожидаемый XML. Также @XmlPath должен работать должным образом.

Ниже приведены некоторые из ошибок, которые я делал. Вы можете проверить, не делаете ли вы их:

  1. У меня было слишком много зависимостей, а некоторые также дублировались. Например, зависимости от com.sun.activation, javax.activation, javax.validation, org.glassfish.jaxb и т.д. Они упоминались в других ответах, поэтому я пробовал все. Лучше удалить все и начать сначала и добавить только один раз. В этом случае достаточно двух, упомянутых в step-2.

  2. Ответы, упомянутые в большей части сообщения на Stackoverflow, относятся к старой версии. Включая статьи и блоги на различных сайтах. Поскольку после Java 11 произошли некоторые изменения, лучше используйте последнюю версию и шаги, упомянутые в этом ответе или другом ответе, предоставленном по ссылке выше.

  3. Убедитесь, что вы очистили и перестроили проект maven, потому что иногда dependencies не добавляются напрямую при сохранении файла pom.xml. По крайней мере, в моем случае, когда я использовал Intellij IDE. Я делал clean и build каждый раз, когда добавлял зависимость, чтобы убедиться, что со стороны Maven все в порядке.

Это все, что я считаю достаточным, чтобы заставить эту работу работать. Если вы все еще сталкиваетесь с какой-либо проблемой, оставьте комментарий в другом сообщении или здесь. Я постараюсь ответить, если смогу. Хорошего дня.

person BATMAN_2008    schedule 13.05.2021