Я пытаюсь получить параметры из JSON в запросе POST. Это кажется очень простым процессом, и я прочитал множество сообщений об этом, но мне что-то здесь не хватает, так как я получаю объект обратно, но поля внутри этого объекта равны нулю. В моем POST у меня есть следующий JSON ...
{
"client": "1",
"forTopic": "topic"
}
А вот мой метод POST внутри моего сервлета ...
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
String requestBody = RESTUtil.getRequestBody (request);
log.debug (requestBody);
try
{
JAXBContext context = JAXBContext.newInstance (ClientAndTopicParameters.class);
Unmarshaller unmarshal = context.createUnmarshaller ();
unmarshal.setProperty (UnmarshallerProperties.MEDIA_TYPE, "application/json");
unmarshal.setProperty (UnmarshallerProperties.JSON_INCLUDE_ROOT, true);
ClientAndTopicParameters params = (ClientAndTopicParameters) unmarshal.unmarshal (new StreamSource (new StringReader (requestBody)), ClientAndTopicParameters.class).getValue ();
log.debug ("params = " + params);
log.debug ("client = " + params.client);
log.debug ("forTopic = " + params.forTopic);
}
catch (JAXBException e)
{
log.error ("Unable to get Client and Topic parameters from POST.", e);
}
}
Наконец, вот мой класс ClientAndTopicParameters ...
@XmlRootElement
public class ClientAndTopicParameters
{
@XmlElement public String client;
@XmlElement public String forTopic;
}
В результате получится следующий ...
2018 Aug 24 17:44:55,806 DEBUG [MyServlet ] params = mypackage.ClientAndTopicParameters@2995a298
2018 Aug 24 17:44:55,806 DEBUG [MyServlet ] client = null
2018 Aug 24 17:44:55,806 DEBUG [MyServlet ] forTopic = null
Как видите, это довольно простые вещи. Я предполагаю, что мне не хватает чего-то маленького, чего я просто не вижу. Приветствую любые мысли и идеи. Для справки я использую JAXB v2.3.0
Я не уверен, что это правильный m4gic. Я использую JAXB для маршалинга и демаршалинга JSON для других моих объектов. Следовательно, unmarshal.setProperty (UnmarshallerProperties.MEDIA_TYPE, «application / json»); Единственная разница в том, что в этом случае я не указываю XMLRoolElement. Обычно у меня есть @XmlRoolElement (name = "MyObject"). Но в данном случае JSON - это объект, а не объект, указанный в JSON. Например ... {"MyObject": {JSON DATA ...}}. Вместо этого у меня есть {JSON DATA ...}. Думаю, я ищу, как указать, что этот JSON предназначен для моего объекта ClientAndTopicParameters.
Привет, да, я не знал, что jaxb может справиться с этим. Таким образом, кажется, что можно использовать JAXB для маршаллинга / демаршаллинга JSON, ЕСЛИ вы используете какие-то дополнительные технологии, такие как Jackson или Moxy ... Эти дополнительные технологии могут обрабатывать JSON самостоятельно, для меня было бы яснее использовать только Jackson (как родной JSON parser / serializer), чем использовать JAXB таким образом. Я думаю, что Джексон в этом намного лучше. Использование аннотаций XML для аннотирования POJO для обработки JSON меня сбивает с толку.
Вы должны добавить к вопросу, какую версию jaxb вы используете, это поможет воспроизвести вашу проблему.
Спасибо @ m4gic. Хороший момент, добавлю версию. Кроме того, я выбрал JAXB, чтобы он обрабатывал объекты JPA, которые я использую. Я признаю, что я не исследовал Джексона. Я обязательно посмотрю.




Решение состоит в том, чтобы сериализовать желаемый объект и поиграть с флагом includeRoot. Если вы установите его в false, вы получите желаемый результат.
import java.io.StringReader;
import java.io.StringWriter;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.PropertyException;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.transform.stream.StreamSource;
import org.eclipse.persistence.jaxb.UnmarshallerProperties;
@XmlRootElement
public class ClientAndTopicParameters
{
@XmlElement public String client;
@XmlElement public String forTopic;
public static void main(String[] args) {
try
{
boolean includeRoot = true;
JAXBContext context = JAXBContext.newInstance (ClientAndTopicParameters.class);
Unmarshaller unmarshal = context.createUnmarshaller ();
unmarshal.setProperty (UnmarshallerProperties.MEDIA_TYPE, "application/json");
unmarshal.setProperty (UnmarshallerProperties.JSON_INCLUDE_ROOT, includeRoot);
parseAndPrint(unmarshal, "{ \"client\": \"1\", \"forTopic\": \"topic\"}");
StringWriter sw = marshallDesiredObject(context, includeRoot);
parseAndPrint(unmarshal, sw.toString());
}
catch (JAXBException e)
{
System.out.println("Unable to get Client and Topic parameters from POST.");
e.printStackTrace();
}
}
private static StringWriter marshallDesiredObject(JAXBContext context, boolean includeRoot)
throws JAXBException, PropertyException {
Marshaller marshal = context.createMarshaller ();
marshal.setProperty (UnmarshallerProperties.MEDIA_TYPE, "application/json");
marshal.setProperty (UnmarshallerProperties.JSON_INCLUDE_ROOT, includeRoot);
ClientAndTopicParameters cp = new ClientAndTopicParameters();
cp.client = "1";
cp.forTopic = "topic";
StringWriter sw = new StringWriter();
marshal.marshal(cp, sw);
return sw;
}
private static void parseAndPrint(Unmarshaller unmarshal, String requestBody)
throws JAXBException {
System.out.println("requestBody to parse: " + requestBody);
ClientAndTopicParameters params = unmarshal.unmarshal(new StreamSource (new StringReader (requestBody )), ClientAndTopicParameters.class).getValue ();
System.out.println("params = " + params);
System.out.println("client = " + params.client);
System.out.println("forTopic = " + params.forTopic);
}
}
Я использовал эти зависимости:
<dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>org.eclipse.persistence.moxy</artifactId>
<version>2.5.2</version>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.2.11</version>
</dependency>
В вашем коде это единственное, что вам нужно изменить:
unmarshal.setProperty (UnmarshallerProperties.JSON_INCLUDE_ROOT, false);
Вы также должны установить фабрика контекста jaxb для eclipselink ...
Еще раз спасибо @ m4gic. Это было решение. Я знал, что это должно быть что-то простое. На самом деле я пытался просто закомментировать эту строку, где я установил JSON_INCLUDE_ROOT в значение true. Полагая, что по умолчанию будет false. Похоже, это нужно явно указать. Простое изменение, и все работает. Еще раз спасибо за вашу помощь!
JAXB предназначен для маршалинга / демаршалинга файлов XML, а не для чтения содержимого JSON. Вы должны использовать Джексон, Гсон или что-то еще, чтобы читать свое pojo. Здесь вы можете сгенерировать свои pojos после проверки правильной технологии, которую вы хотели бы использовать для синтаксического анализа тела запроса, с этими сгенерированными POJO ваши JSON определенно будут доступны для чтения Jackson / Gson.