jakartaee / jakartaee/messaging

Annotation-Based API for Consuming Messages

Open
#243 6 comments 0 reactions 0 assignees View on GitHub
4.0 CDI integration New Feature use case
Dominant language
Java
Stars
49
Forks
34
PR merge metrics
No merged PRs in 30d

Description

The only means to declare message consumers via configuration or annotation is currently via JMS Message-Driven Beans. A new expressive annotation-based approach modeled after JAX-RS is desired to bring JMS into the future.

A follow-up to an older issue: https://github.com/jakartaee/messaging/issues/134.

Current MDB API Example:
```
import javax.ejb.ActivationConfigProperty;
import javax.ejb.MessageDriven;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.ObjectMessage;

@MessageDriven(activationConfig = {
@ActivationConfigProperty(propertyName = "maxSessions", propertyValue = "3"),
@ActivationConfigProperty(propertyName = "maxMessagesPerSessions", propertyValue = "1"),
@ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
@ActivationConfigProperty(propertyName = "destination", propertyValue = "TASK.QUEUE")
})
public class BuildTasksMessageListener implements MessageListener {

@Override
public void onMessage(Message message) {
try {

if (!(message instanceof ObjectMessage)) {
throw new JMSException("Expected ObjectMessage, received " + message.getJMSType());
}

final ObjectMessage objectMessage = (ObjectMessage) message;

final BuildTask buildTask = (BuildTask) objectMessage.getObject();

doSomethingUseful(buildTask);

} catch (JMSException e) {
// Why can't I throw a JMS Exception
throw new RuntimeException(e);
}
}

// This is the only "useful" code in the class
private void doSomethingUseful(BuildTask buildTask) {
System.out.println(buildTask);
}
}
```

Issues with this API involve:

- User manual required to know what names can be used in `@ActivationConfigProperty`.
- Loosely typed. All values are string, but have an implied type which is not compile-time checked.
- Poor targeting. The metadata for the `onMessage` method is on the class, not the method, making additional methods impossible.
- Too Course-grained. The `MessageListener.onMessage(Message msg)` method is similar to the `HttpServlet.service(ServletRequest req, ServletResponse res)` in being too course-grained and requires boilerplate; casting, message property checking, string parsing.
- EJB-specific. The above API is only available to EJB Message-Driven beans.

Some form of annotation-based approach styled after JAX-RS could solve all of the above issues. For example:

```
import io.breezmq.MaxMessagesPerSession;
import io.breezmq.MaxSessions;

import javax.ejb.MessageDriven;
import javax.jms.JMSException;
import javax.jms.JMSMessageDrivenBean;
import javax.jms.ObjectMessage;
import javax.jms.QueueListener;
import javax.jms.TopicListener;

@MessageDriven
@MaxSessions(3)
@MaxMessagesPerSession(1)
public class BuildTasksMessageListener implements JMSMessageDrivenBean {

@QueueListener("TASK.QUEUE")
public void processBuildTask(final ObjectMessage objectMessage) throws JMSException {

final BuildTask buildTask = (BuildTask) objectMessage.getObject();

doSomethingUseful(buildTask);

}

@TopicListener("BUILD.TOPIC")
public void processBuildNotification(final ObjectMessage objectMessage) throws JMSException {

final BuildNotification notification = (BuildNotification) objectMessage.getObject();

System.out.println("Something happened " + notification);
}

// This is the only "useful" code in the class
private void doSomethingUseful(BuildTask buildTask) {
System.out.println(buildTask);
}
}
```

Benefits:

- Multiple user-defined message consuming methods allowed.
- Method signature implies message type, avoiding casting.
- Message Properties can be passed as annotated method arguments. (not shown above)
- Strongly-typed annotations replace string properties so names and values are compile-time checked.
- Opens the door for use outside EJB

The above API should be considered a straw-man just to get conversations started.

## Proposals

Actual proposals from the community are welcome, but should achieve or not-conflict with the same 5 benefits. Partial proposals are welcome, such as #241 which focuses on one aspect required to make an annotation-based API work.

- `@MessageConsumer` for discovery #241

File your proposals and mention in the comments below and we'll add it to the list, regardless of state.

TODO: find JMS 2.1 proposal and link it

## Related

Contributor guide

Open the contributing guide

Research direction

No target files or tests are identified. Start by reading the older issue #134 and the discovery proposal #241, then compare possible designs against the five stated benefits and the JMS and EJB constraints. Done would be an agreed, concrete annotation-based API proposal rather than the current straw-man discussion.

Written by the indexing model from the issue text.

Assessment

Tech stack
java
Domain
api, backend-api-design
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
20/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.