[Java] Change the value of a variable in debug without changing source or breaking (use conditional breakpoints)

3 minute read

What do you do when you write a program and want to test a route that you wouldn’t normally take? Generally, I think that it will be executed as follows.

  • Set breakpoints at specific points
  • Perform the action you want to test
  • Wait until you reach a breakpoint
  • Manually change the value when you reach a breakpoint

However, there are times when I want to repeat the operation several times with the value changed, and in this case I want the value to be automatically rewritten. Have you ever wondered?

Actually, this can be achieved by using conditional breakpoints, but I leave it as there are many veteran people who do not know quite well.

Prerequisites and background

Sample code and assumed pattern

A method that executes RestAPI and performs state check → parsing → model conversion. (Content is not particularly important)

    public JmaFeed getFeed() {
        ResponseEntity<String> response = restTemplate.getForEntity(uri, String.class);
        if (!response.hasBody()) {
            return null;
        }

        String responseBody = response.getBody();
        if (isNull(responseBody)) {
            return null;
        }

        JmaXmlFeed xml = xmlParser.read(response.getBody(), JmaXmlFeed.class);
        if (isNull(xml.getTitle())) {
            return null;
        }

        return modelMapper.map(xml, JmaFeed.class);
    }

This method can’t happen normally

  1. isNull(responseBody)
  2. isNull(xml.getTitle())

Suppose you want to check the condition for many times. Note that the value of xml.getTitle() can be rewritten with xml.setTitle() and the source code is not changed.

Background: Conditional breakpoints

When debugging with the IDE, it is possible to set conditions for breakpoints. This is sometimes called a conditional breakpoint.

■Screen when right-clicking on a breakpoint of IntelliJ

image.png


The usual usage of this condition is to set “if variable A is 0” or “if variable B is null”. In other words, write as follows.

■ Example: Break when the variable responseBody is null image.png

Now you can stop at a breakpoint when responseBody = null.

How to change the value of a variable without changing source or breaking when debugging

Here is the main issue. I will explain two methods.

Assign to variable value at conditional breakpoint

The condition of the conditional breakpoint should return true/false at the end, and you can do anything in the middle. So it is possible to set such conditions.

condition


(responseBody = null) != null

image.png

This formula is as you see

  • Substitute null for responseBody
  • Determine if responseBody is not null

, The condition is always false and there is no break. In other words, the responseBody could be rewritten automatically without stopping at the breakpoint.

Call setter at conditional breakpoint

Next, it is a method that satisfies the condition isNull(xml.getTitle())) in 2., but it requires more work than before. Because in our program we can change the value with xml.setTitle(null), but most setters are void methods. That means you can’t compare the method result to anything, and you can’t set an expression like xml.setTitle(null) != null to a condition.

Therefore, try the following formula.

condition


Optional.of("a").map(x -> {xml.setTitle(null); return false; }).get()

This was achieved by using Optional#map that can take a method as an argument as a method of returning false while executing xml.setTitle(null). I think it can be realized by other methods as long as it can return an arbitrary value with a lambda expression as an argument.

By the way, in the case of Eclipse, just setting xml.setTitile(null) will rewrite the value as expected. There seems to be differences in conditions depending on the IDE, so please check the behavior of the IDE you are using.

Summary

A summary of how to change the value of a variable without breaking when debugging.

1. Assign to variable value at conditional breakpoint

Substitute and write the condition that becomes false

condition example


(responseBody = null) != null

2. Call a setter with a conditional breakpoint

Call setter with Optional#map and return false

condition


Optional.of("a").map(x -> {xml.setTitle(null); return false; }).get()

I think you can do the same thing in other languages by using the same mechanism.