Я пытаюсь сделать что-то, что мне показалось довольно простым, а именно использовать JSON для сохранения контейнера POJO с различными свойствами в нем.
После прочтения о различных способах маршалирования / демаршализации JSONбез всего, что связано с веб-сервисами, я подумал, что MOXy будет лучшим способом, поскольку он может обрабатывать аннотации без JAXB POJO.Я использую MOXy 2.7.3.
Однако я столкнулся с двумя проблемами:
Я использую Maven со следующей зависимостью:
<dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>org.eclipse.persistence.moxy</artifactId>
<version>2.7.3</version>
</dependency>
Однако, если я не включу эту зависимость в JAR-файл GlassFish:
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>javax.json</artifactId>
<version>1.1.2</version>
</dependency>
Я получаю следующее исключение при попытке демонтажа (маршалинг работает нормально):
Caused by: Exception [EclipseLink-25004] (Eclipse Persistence Services - 2.7.3.v20180807-4be1041): org.eclipse.persistence.exceptions.XMLMarshalException
Exception Description: An error occurred unmarshalling the document
Internal Exception: javax.json.JsonException: Provider org.glassfish.json.JsonProviderImpl not found
at org.eclipse.persistence.exceptions.XMLMarshalException.unmarshalException(XMLMarshalException.java:122)
at org.eclipse.persistence.internal.oxm.record.json.JsonStructureReader.parse(JsonStructureReader.java:148)
...
Почему MOXy нужна зависимость GlassFish JsonProviderImpl?
Мне нужно объявить @XmlRootElement
в моем классе контейнера.Не уверен, почему, но это так, даже если я использую marshaller.setProperty(MarshallerProperties.JSON_INCLUDE_ROOT, true);
, который, кажется, по умолчанию.Если у меня нет @XmlRootElement
, я получаю следующее исключение при попытке демонтировать (маршалинг работает отлично):
Caused by: Exception [EclipseLink-25008] (Eclipse Persistence Services - 2.7.3.v20180807-4be1041): org.eclipse.persistence.exceptions.XMLMarshalException
Exception Description: A descriptor with default root element stringValue was not found in the project
Возможно, я просто запутался,но из документов видно, что MOXy может работать с POJO?
Вот пример кода, показывающего, что я делаю:
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.Reader;
import java.io.Writer;
import java.nio.file.Paths;
import java.time.ZonedDateTime;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import org.eclipse.persistence.jaxb.JAXBContextFactory;
import org.eclipse.persistence.jaxb.MarshallerProperties;
public class MoxyTest
{
public static void main(String[] args) throws Exception
{
// Create an instance of the container to be written/read with JSON
TestContainer testContainer = new TestContainer();
testContainer.stringValue = "test string";
testContainer.intValue = 5;
testContainer.zonedDateTimeValue = ZonedDateTime.now().minusMonths(1);
// Note that JAXBContextFactory is specific to MOXy, this was done to avoid having to create a jaxb.properties
// See /6847881/mogu-li-ya-zamenit-jaxb-properties-kodom and
// https://stackoverflow.com/questions/28676613/set-moxy-as-jaxb-provider-without-properties-file-in-the-same-package
JAXBContext jaxbContext = JAXBContextFactory.createContext(new Class[] {TestContainer.class}, null);
Marshaller marshaller = jaxbContext.createMarshaller();
// By default the marshaller will output XML, we have to tell it to use JSON instead
marshaller.setProperty(MarshallerProperties.MEDIA_TYPE, "application/json");
File dataFile = Paths.get("/temp", "datafile.json").toFile();
Writer writer = new FileWriter(dataFile);
marshaller.marshal(testContainer, writer);
writer.close();
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
// By default the unmarshaller will try to read XML, we have to tell it to use JSON instead
unmarshaller.setProperty(MarshallerProperties.MEDIA_TYPE, "application/json");
// Determine the location for the file which is used to persist the data
if (dataFile.exists() && (dataFile.length() > 0))
{
Reader reader = new FileReader(dataFile);
TestContainer readTestContainer = (TestContainer) unmarshaller.unmarshal(reader);
System.out.println(readTestContainer.intValue);
System.out.println(readTestContainer.stringValue);
System.out.println(readTestContainer.zonedDateTimeValue);
reader.close();
}
}
}
И тестовый контейнер (с @XmlRootElement
):
import java.time.ZonedDateTime;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement(name = "testContainer")
public class TestContainer
{
public String stringValue;
public int intValue;
public ZonedDateTime zonedDateTimeValue;
}
Обратите внимание, что для дополнительной удивительности, возможно, кто-то может ответить, почему ZonedDateTime будет правильно маршалировать, но не демаршировать (результат равен null
)?Вот результаты запуска MoxyTest
:
5
test string
null