Search code examples
javajmxactivemq-artemis

Can't read bytes message via JMX in ActiveMQ Artemis


I am reading a message via JMX. If it is text then everything is OK, but if it is byte then it gives such an error. I can't figure out how I should read a byte message and get its text in a string.

Here's my Java code:

public static JMXMessage showMessage(QueueControl queueControl) {
    JMXHeaders jmxHeaders;
    JMXMessage jmxMessage;
    String body;
    String replyTo = null;
    String correlationId = null;
    try {
        CompositeData[] messages = queueControl.browse();
        j = queueLength - i;
        if (j > queueLength - 1) {
            i = 1;
            j = queueLength - i;
        }
        if (j < 0) {
            i = queueLength;
            j = 0;
        }

        TabularData stringProps = (TabularData) messages[j].get(CompositeDataConstants.STRING_PROPERTIES);
        for (CompositeData o : (Collection<CompositeData>) stringProps.values()) {
            Object key = o.get("key");
            if (key.equals("JMSReplyTo")) {
                replyTo = o.get("value").toString();
            }
            if (key.equals("JMSCorrelationID")) {
                correlationId = o.get("value").toString();
            }
        }
        jmxHeaders = new JMXHeaders(messages[j].get(CompositeDataConstants.TYPE).toString(),
                messages[j].get(CompositeDataConstants.EXPIRATION).toString(),
                messages[j].get(CompositeDataConstants.DURABLE).toString(),
                replyTo,
                messages[j].get(CompositeDataConstants.MESSAGE_ID).toString(),
                messages[j].get(CompositeDataConstants.TIMESTAMP).toString(),
                correlationId,
                messages[j].get(CompositeDataConstants.PRIORITY).toString());
        body = (String) messages[j].get(CompositeDataConstants.TEXT_BODY);
        jmxMessage = new JMXMessage(jmxHeaders, body);

        return jmxMessage;
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}

Error code:

Caused by: java.lang.RuntimeException: javax.management.openmbean.InvalidKeyException: Argument key="text" is not an existing item name for this CompositeData instance.
    at jmxClientUIPConsole.BuildGet.showMessage(BuildGet.java:155)
    at jmxClientUIPConsole.DConsoleFrameControllerGetMessage.viewMessage(DConsoleFrameControllerGetMessage.java:166)
    ... 62 more
Caused by: javax.management.openmbean.InvalidKeyException: Argument key="text" is not an existing item name for this CompositeData instance.
    at java.management/javax.management.openmbean.CompositeDataSupport.get(CompositeDataSupport.java:270)
    at jmxClientUIPConsole.BuildGet.showMessage(BuildGet.java:150)
    ... 63 more

That is the error in this line:

body = (String) messages[j].get(CompositeDataConstants.TEXT_BODY);

How can I then determine in this method what message came to me (byte or text)? And how do I get the message in bytes from the queue?


Solution

  • The bodies of a JMS BytesMessage and TextMessage are serialized differently because the former is a byte[] and the latter is a String. You are attempting to get the text body out of a BytesMessage which doesn't exist and therefore you receive the InvalidKeyException.

    However, you can detect the kind of message it is and then adjust accordingly, e.g.:

          QueueControl queueControl = ...
          CompositeData[] messages = queueControl.browse();
          for (CompositeData message : messages) {
             if ((byte) message.get(CompositeDataConstants.TYPE) == (byte) 4) {
                System.out.println("This is a BytesMessage");
             } else {
                System.out.println("This is a TextMessage");
             }
          }
    

    If you want to get the byte[] body of the message you can do so like this:

    byte[] body = (byte[]) message.get(CompositeDataConstants.BODY);
    

    Of course, in order to actually decode they byte[] into a String for example you'll need to know how it was encoded in the first place. String objects in Java can be encoded many different ways although the most common is probably using UTF-8 in which case the code would look something like:

    String body = Strings.getString((byte[]) message.get(CompositeDataConstants.BODY), StandardCharsets.UTF_8);