Как избежать » в строке json?

#spring-boot #gson #activemq

#весенняя загрузка #gson #activemq

Вопрос:

Приложение Spring boot

В build.gradle:

 implementation 'com.google.code.gson:gson:2.7'
  

Здесь JMSConfiguration:

 import org.springframework.boot.autoconfigure.jms.DefaultJmsListenerContainerFactoryConfigurer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.jms.config.DefaultJmsListenerContainerFactory;
import org.springframework.jms.config.JmsListenerContainerFactory;
import org.springframework.jms.support.converter.MappingJackson2MessageConverter;
import org.springframework.jms.support.converter.MessageConverter;
import org.springframework.jms.support.converter.MessageType;
@Configuration
@ComponentScan(basePackages = "ru.otus.software_architect.eshop")
public class JMSConfiguration {

    @Bean
    public JmsListenerContainerFactory<?> myFactory(ConnectionFactory connectionFactory,
                                                    DefaultJmsListenerContainerFactoryConfigurer configurer) {
        DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
        // This provides all boot's default to this factory, including the message converter
        configurer.configure(factory, connectionFactory);
        // You could still override some of Boot's default if necessary.
        return factory;
    }

    @Bean
    public MessageConverter jacksonJmsMessageConverter() {
        MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter();
        converter.setTargetType(MessageType.TEXT);
        converter.setTypeIdPropertyName("_type");
        return converter;
    }
}
  

Вот как я отправляю сообщение в ActiviveMQ:

 private void sendMessageToMessageBroker(NotifyActionEnum action, int orderId) {
        JsonObject json = new JsonObject();
        json.addProperty("email", UserService.getCurrentUserName());
        json.addProperty("action", action.name().toLowerCase());
        json.addProperty("orderId", orderId);
        JmsTemplate jmsTemplate = context.getBean(JmsTemplate.class);
        String message = json.toString();
        jmsTemplate.convertAndSend(ESHOP_QUEUE, message);
        logger.info("sendMessageToMessageBroker: success_sent_message_to_MB: "   message);
    }
  

Здесь, в журнале:

success_sent_message_to_MB :

 {"email":"someemail@email.com","action":"order_update","orderId":14}
  

Неплохо.

Но в ActiveMQ в моей очереди сообщение выглядит следующим образом:

   "{"email":"a_subscriber@mail.ru","action":"order_update","orderId":4,"createdAt":"2020-09-13T11:32:09.976 0300"}"
  

Вот скриншот:

введите описание изображения здесь

И я запускаю свое другое приложение (потребитель). И это нарушается при попытке получить дату из json:

 JsonElement messageJson = GsonUtil.parser.parse(message);
String action = messageJson.getAsJsonObject().get("action").getAsString(); // here broken
  

Я получаю сообщение об ошибке:

 Caused by: java.lang.IllegalStateException: Not a JSON Object: "{"email":"a_subscriber@mail.ru","action":"order_update","orderId":4,"createdAt":"2020-09-13T11:32:09.976 0300"}"
  

Как я могу избежать » в строке?

Мне нужно поставить в очередь следующую строку:

 {"email":"someemail@email.com","action":"order_update","orderId":14}
  

Комментарии:

1. Что-то помещает строку в двойные кавычки, и для этого нужно экранировать двойные кавычки в строке, чтобы это сработало.

2. @Steve Почему в очереди отображается строка с » ?

3. Я предполагаю, это из-за кавычек в начале и конце строки. Какой бы механизм ни добавлял эти кавычки, он также экранирует кавычки в середине строки, ставя » перед каждой из них. Почему это происходит, я не знаю.

4. Что MessageConverter вы настроили для своего JmsTemplate ? Используете ли вы значение по умолчанию, SimpleMessageConverter которое преобразует a String в javax.jms.TextMessage ?

5. @JustinBertram Я обновил свой пост

Ответ №1:

Попробуйте использовать значение по умолчанию MessageConverter (т. Е. SimpleMessageConverter ) и отправить свое сообщение как byte[] , например:

 private void sendMessageToMessageBroker(NotifyActionEnum action, int orderId) {
   JsonObject json = new JsonObject();
   json.addProperty("email", UserService.getCurrentUserName());
   json.addProperty("action", action.name().toLowerCase());
   json.addProperty("orderId", orderId);
   JmsTemplate jmsTemplate = context.getBean(JmsTemplate.class);
   String message = json.toString();
   jmsTemplate.convertAndSend(ESHOP_QUEUE, message.getBytes());
   logger.info("sendMessageToMessageBroker: success_sent_message_to_MB: "   message);
}
  

Когда вы отправляете сообщение в виде a , byte[] the SimpleMessageConverter преобразует его в a javax.jms.BytesMessage . Когда ваш потребитель получает сообщение, он может преобразовать byte[] в String вот так:

 String messageAsString;
if (message instanceof BytesMessage) {
   BytesMessage bytesMessage = (BytesMessage) message;
   byte[] buffer = new byte[(int) bytesMessage.getBodyLength()];
   bytesMessage.readBytes(buffer);   
   messageAsString = new String(buffer);
}
JsonElement messageJson = GsonUtil.parser.parse(messageAsString);
String action = messageJson.getAsJsonObject().get("action").getAsString();
  

Я считаю, что отправка сообщения как byte[] позволит избежать нежелательного экранирования.

Комментарии:

1. можно ли понять, что производитель отправляет через веб-консоль?

2. Я не уверен, что вы имеете в виду.

3. Я хочу увидеть некоторую информацию, например {"email":"someemail@email.com","action":"order_update","orderId":14} , с помощью инструментов пользовательского интерфейса

4. Я не уверен, что веб-консоль ActiveMQ будет декодировать byte[] в String для отображения. Имейте в виду, что сообщения (даже текстовые сообщения) могут быть закодированы многими различными способами, и у брокера не обязательно есть информация, необходимая для декодирования сообщения в формат, доступный для чтения человеком (при условии, что такой формат существует).

5. Я считаю, что веб-консоль не может декодировать из byte[] в string, потому что byte [] может быть чем угодно. но order_id может быть частью очень полезной информации, которую следует воспринимать как человеческий язык

Ответ №2:

Я использую urlEncode/decode для отправки сообщения в ActiveMQ

В моем контроллере:

 private String publishToMessageBroker(NotifyActionEnum action, int orderId) {
        logger.info("publishToMessageBroker:");
        JsonObject json = new JsonObject();
        json.addProperty("email", UserService.getCurrentUserName());
        json.addProperty("action", action.name().toLowerCase());
        json.addProperty("orderId", orderId);
        json.addProperty("createdAt", DateUtil.date2String(new Date(), DateUtil.JSON_DATE_FORMAT));
        String message = json.toString();
        String urlEncodeMessage = StringUtll.urlEncode(message);
        jmsTemplate.convertAndSend(ESHOP_QUEUE, urlEncodeMessage);
        logger.info("publishToMessageBroker: success_sent_message_to_MB: "   message);
        return "Message was success published on Message Broker!"; // can use as response
}
  

И теперь в ActiveMQ сообщение выглядит так:

 "{"email":"myemail@mail.com","action":"order_delete","orderId":6,"createdAt":"2020-09-19T12:20:57.844+0300"}"
  

И теперь в получателе сообщений я декодирую сообщение

  @JmsListener(destination = ESHOP_QUEUE)
    public void receiveMessage(String urlEncodeMessage) {
        try {
            String urlDecodeMessage = StringUtil.urlDecode(urlEncodeMessage);
            String pureDecodeMessage = StringUtil.removeFirstAndLastQuotes(urlDecodeMessage);
            JsonElement messageJson = GsonUtil.parser.parse(pureDecodeMessage);
  

И теперь все работает нормально. Больше никаких escape-символов, таких как «».

После декодирования URL я получаю чистый json:

 "{"email":"myemail@mail.com","action":"order_delete","orderId":6,"createdAt":"2020-09-19T12:20:57.844 0300"}"