Using AssertJ to Verify a Complex Exception

9:01 AM 0 Comments

AssertJ just went up another notch in my book today

For a particular unit test, I needed to verify the contents of an exception. Originally, I figured said contents where just part of the exception message:

assertThatCode(() -> doMyExceptionalThing())
    .hasMessage("This is the error message")

However, that assertion failed because, in the case that this particular exception has a cause, it has two messages to pick from (more on that in a moment) and it chooses the message from the cause instead of the message I wanted.

I could do something like this to get it to work:

try {
} catch ( SomeException ex ) {
    ErrorDomainObject o = ex.getError();

    // this is the description I need,
    // not the cause's description!
        .isEqualTo("This is the error message");

But that would break my heart. (And we wouldn't want that... just to clarify)

So, I tried some of AssertJ's matching features:

assertThatCode(() -> doMyExceptionalThing())
    .matches(ex -> "This is the error message"
            ((SomeException) ex)


And then, I came upon hasFieldOrPropertyWithValue. Hmm...

Could something like this possibly work?

assertThatCode(() -> doMyExceptionalThing())
        "This is the error message");

And it did! All hail AssertJ for helping me create a clean, readable assertion, even in this slightly more complex scenario.


Configuring Wacom Tablet in Ubuntu 16.04 for Large Monitors

10:36 AM , , 0 Comments

This morning, I needed to sign a document for work. I hate the process of printing something out, signing it, scanning it, and mailing it back.

So I busted out my Wacom Tablet and plugged it into my Linux box and, lo, it recognized it!

The problem, though,  was that writing in my typical lettering (maybe about 1/4 inch height on paper) was coming out 4-5 times that size on the screen, making adding my signature to the form impractical.

Long story short, I wasn't able to find a setting to change the pen distance -> mouse distance ratio, but I did find that if I increased the available area that the pen was mapped to, then it did the trick.

So, here is what I did:

> xsetwacom --list devices

Wacom Bamboo Connect Pen stylus  id: 11 type: STYLUS
Wacom Bamboo Connect Pen eraser  id: 18 type: ERASER    
Wacom Bamboo Connect Pad pad     id: 20 type: PAD

> xsetwacom --get 11 Area

Option "Area" "0 0 14720 9200"

> xsetwacom --set 11 Area "0 0 73600 46000"

At that point, the text looked great!


Integrating spring-security with spring-kafka

8:02 PM 0 Comments

It's not uncommon for a message on a bus to have a user as part of its metadata. In my particular example at my workplace, we had the following very simple use case:

A user creates a task in our system (not unlike a task in, say, Todoist), and the creation of that task is written to a Kafka topic for propagation to other systems. One service consumes this topic to translate each message into an Elasticsearch record. That service finds it useful to know which user in our application created the task.

To achieve this, we at least need to have user information in the message. And it would be nice for the platform to take care of this concern for us.

In our case, the currently logged in user is available through the Spring Security API, so ideally, we'd configure Spring Kafka to read the user from and write the user to the Spring Security SecurityContext with producing and consuming messages.

Spring Kafka makes this simple.

Augmenting Kafka Messages with the Logged In User

First, we need to add the logged in user for each Kafka message. The way we did this was by extending MessagingMessageConverter:

public SpringSecurityAwareMessagingMessageConverter
    extends MessagingMessageConverter {
  protected Object convertPayload(Message message) {
    String payload = (String)super.convertPayload(message);
    Authentication auth =
    if ( auth != null && auth.isAuthenticated() ) {
      return new AsUser(payload, auth);
    } else {
      return new AsUser(payload, null);

This converter wraps the payload on the way out in an envelope that contains the user as pulled from the Security Context. While we probably don't want to simply throw the entire Authentication object in our message, I've done it here just to keep the code simple.

Setting Up a Security Context Based on each Kafka Message

Second, we need to unwrap the message. We can do this also in the same message converter, placing it in the Security Context:

protected Object extractAndConvertValue
    (ConsumerRecord record, Type type) {
    Object value = super.extractAndConvertValue(record, type);
    if ( value instanceof AsUser ) {

      UsernamePasswordAuthenticationToken token =
        new UsernamePasswordAuthenticationToken
          (((AsUser)value).getUser(), null, new ArrayList<>());


      return ((AsUser)value).getMessage();
    return value;

We also do some cleanup once the method invocation is completed in case the same thread is used to process another message:

public SpringSecurityAwareMessageHandlerFactory
    extends DefaultMessageHandlerFactory {
  public InvocableHandlerMethod
    createInvocableHandlerMethod(Object bean, Method method) {
    InvocableHandlerMethod m =
      new InvocableHandlerMethod(bean, method) {
        public Object invoke
          (Message message, Object... providedArgs)
          throws Exception {
          try {
            return super.invoke(message, providedArgs);
          } finally {

    HandlerMethodArgumentResolverComposite handlers =
      new HandlerMethodArgumentResolverComposite();



    return m;

The nice thing about this approach is that these can be used to abstract away the transport of the user. Also, consumers can reuse or otherwise exercise code that uses the SecurityContextHolder to derive who the user is.

Never Trust the Client

Of course, there are problems with this approach. Hypothetically, anyone with access to the Kafka cluster can write messages to this topic and claim a user. If this is a concern, then we can use a claim-based approach to transmit, say, a signed JWT as the user, which, depending on the needs of the consumer, can be used to validate against the issuer. This will definitely slow down processing, so you'll have to weigh the benefits.

I've posted the code as an example in my Github repo. Enjoy!