Ten ways in which JMS 2.0 means writing less code
Here are ten simple examples that demonstrate how JMS 2.0 requires less code than JMS 1.1.
Contents
- Single JMSContext instead of separate Connection and Session objects
- Use of try-with-resources block means no need to call close
- No need to pass in two parameters when creating a session in Java SE
- No need to pass in any parameters when creating a session in a Java EE transaction
- New JMSProducer object supports method chaining
- No need to save a JMSProducer in a variable; simply instantiate on the fly
- In Java EE, injecting a JMSContext means you don’t need to create or close it
- When sending, no need to instantiate a Message object
- Receiving synchronously, can receive mesage payload directly
- Receiving asynchronously: no need for a cast before extracting message body.
- Related pages
Single JMSContext instead of separate Connection and Session objects
The JMS 2.0 simplified API introduces a new object, JMSContext
, which provides the same functionality as the separate Connection
and
Session
objects in the JMS 1.1 API:
JMS 1.1
Connection connection = connectionFactory.createConnection();
Session session = connection.createSession(false,Session.AUTO_ACKNOWLEDGE);
JMS 2.0
JMSContext context = connectionFactory.createContext(JMSContext.SESSION_TRANSACTED);
Use of try-with-resources block means no need to call close
Failing to close a Connection
after use may cause your application to run out of resources.
JMS 1.1
In JMS 1.1 the best way to make sure your connection gets closed after use is to call close()
in a finally
block:
try {
Connection connection = connectionFactory.createConnection();
try {
Session session = connection.createSession(false,Session.AUTO_ACKNOWLEDGE);
... etc ...
} finally {
connection.close();
}
} catch (JMSException ex) {
ex.printStackTrace();
}
This is rather verbose. To make things worse, if you get an exception in the body of the try
block, followed by an exception in close()
,
the first exception will be lost, even though the first exception is probably the root cause of the failure.
JMS 2.0
In JMS 2.0 the Connection
object implements the java.lang.AutoCloseable
interface. This means that if you create the Connection
object in a try-with-resources block the close
method will be called automatically at the end of the block.
try (Connection connection = connectionFactory.createConnection();){
... etc ...
} catch (JMSException ex) {
ex.printStackTrace();
}
This requires less code. In addition it allows exceptions to be handled better: if you get an exception in the body of the try block, followed by an exception in close()
, the
first exception will be nicely nested within the first, so you can easily identify the root cause.
The same syntax may be used when creating a JMSContext
.
No need to pass in two parameters when creating a session in Java SE
…one is all you need:
JMS 1.1
Session session = connection.createSession(true,Session.SESSION_TRANSACTED);
JMS 2.0
Session session = connection.createSession(Session.SESSION_TRANSACTED);
There are similar methods for creating a JMSContext
No need to pass in any parameters when creating a session in a Java EE transaction
If you create a Session
in a Java EE transaction, the arguments to createSession
are ignored.
It says so in the EJB 3.1 spec.
JMS 1.1
But JMS 1.1 still required you to pass in two parameters even though they will be ignored.
// both parameters will be ignored; transactional behaviour is determined by the container
Session session = connection.createSession(false,Session.CLIENT_ACKNOWLEDGE);
JMS 2.0
JMS 2.0 provides a method with no parameters:
// transactional behaviour is determined by the container
Session session = connection.createSession();
New JMSProducer object supports method chaining
The new JMSProducer
object allows message headers, message properties and delivery options to be specified in a single line of code using method chaining
JMS 1.1
MessageProducer messageProducer = session.createProducer(demoQueue);
messageProducer.setPriority(1);
TextMessage textMessage = session.createTextMessage(body);
textMessage.setStringProperty("foo", "bar");
messageProducer.send(textMessage);
JMS 2.0
TextMessage textMessage = context.createTextMessage(body); context.createProducer().setPriority(1).setProperty(“foo”, “bar”).send(demoQueue, textMessage);
No need to save a JMSProducer in a variable; simply instantiate on the fly
The new JMSProducer
object is a lightweight object so there’s no need to save it in a variable; simply instantiate one on the fly when needed
JMS 1.1
MessageProducer
is expensive so need to reuse it.
MessageProducer messageProducer = session.createProducer(demoQueue);
messageProducer.send(message1);
messageProducer.send(message2);
JMS 2.0
JMSProducer
is cheap, no need to save in variable
context.createProducer().send(demoQueue,message1);
context.createProducer().send(demoQueue,message2);
In Java EE, injecting a JMSContext means you don’t need to create or close it
JMS 1.1
try {
Connection connection = connectionFactory.createConnection();
try {
Session session = connection.createSession(false,Session.AUTO_ACKNOWLEDGE);
MessageProducer messageProducer = session.createProducer(demoQueue);
TextMessage textMessage = session.createTextMessage(body);
messageProducer.send(textMessage);
} finally {
connection.close();
}
} catch (JMSException ex) {
ex.printStackTrace();
}
JMS 2.0
try {
context.createProducer().send(inboundQueue, body);
} catch (JMSRuntimeException ex){
ex.printStackTrace();
}
When sending, no need to instantiate a Message object
JMS 1.1
Need to create a message object of the appropriate type and then set its body:
MessageProducer messageProducer = session.createProducer(demoQueue);
TextMessage textMessage = session.createTextMessage("Hello world");
messageProducer.send(textMessage);
JMS 2.0
In JMS 2.0, simply pass the message body into the send
method:
context.createProducer().send(demoQueue,"Hello world");
Note that you can do this even when you want to set message properties since these can be set on the JMSProducer
.
Receiving synchronously, can receive mesage payload directly
JMS 1.1
When receiving synchronously, so you are given a Message
object and need to cast it to the appropriate subtype before you can extract its body:
MessageConsumer messageConsumer = session.createConsumer(demoQueue);
TextMessage textMessage = (TextMessage) messageConsumer.receive(1000);
if (textMessage==null){
return "Received null";
} else {
return "Received "+textMessage.getText();
}
JMS 2.0
JMS 2.0 allows you to receive the message body directly.
JMSConsumer consumer = context.createConsumer(demoQueue);
return "Received " + consumer.receiveBody(String.class, 1000);
Note the lack of casting, or special null handling.
Receiving asynchronously: no need for a cast before extracting message body.
JMS 1.1
When receiving a message asynchronously, the message passed to the onMessage
method is a javax.jms.Message
You need to cast it to the expected subtype before you can extract the body. If the message is an ObjectMessage
this gives you a Serializable
body which you have to cast a second time to the expected body type.
public void onMessage(Message m){
MyObject myObj = (MyObject)((ObjectMessage)m).getObject();
...
JMS 2.0
A new method getBody
allows you to extract the body from the Message
without the need to cast it to the appropriate subtype first. This is particularly handy for ObjectMessages, as it avoids a double cast to extract the object payload
public void onMessage(Message m){
MyObject myObj = m.getBody(MyObject.class);
...