4

I am looking for a way to dump the values of variables whenever it changes eg. to stdout, without manually writing the logging or println code, so that I can inspect what happens dynamically. If possible, the class name and source file line number should also be included.

For example, with the following:

public class SomeClass {

    public static void main(java.lang.String[] args) {
        someVariableA = 0;
        someVariableB = 5;
        someVariableC = 8;
        someVariableD = someVariableA + someVariableB;
        someVariableD = 9;


    }

}

There should be some output like:

someVariableD = 5 at SomeClass.main(SomeClass.java:[lineNumber])
someVariableD = 9 at SomeClass.main(SomeClass.java:[lineNumber])

I should be able to do this without writing much code, and disable this without deleting much code. It should be able to show every change to every variable.

With logging frameworks like log4j, I still have to write the code to dump a variable?

Is this something that I can do with a library/framework, a setting in the Java compiler or JVM, or with some IDE?

Pshemo
  • 122,468
  • 25
  • 185
  • 269
forgodsakehold
  • 870
  • 10
  • 26
  • 4
    Basically no. I think most debuggers will allow you to set a watch point and watch some variables (and "dump" them) when they change. – markspace Jul 14 '18 at 18:39
  • 2
    Why do you think you want to do this? It is not a good substitute for debugging. – Joe C Jul 14 '18 at 18:49
  • You can use dynamic proxy (http://www.baeldung.com/java-dynamic-proxies), but it requires to write proxy code and use setter methods instead of directly asign value to variable. – piradian Jul 14 '18 at 19:13
  • Off-Topic; **Too Broad** as well as **Recommendations**, **Primarily Opinion Based**, that said, Aspects and DynamicProxies let you decorate methods in Java at a time cost. –  Jul 19 '18 at 16:01
  • 1
    [What does your step debugger tell you?](http://stackoverflow.com/questions/25385173/what-is-a-debugger-and-how-can-it-help-me-diagnose-problems). Your question can be answered very quickly and easily with your step-debugger. You should always try and solve your problems with a step debugger before coming to StackOverflow. –  Jul 19 '18 at 16:02

2 Answers2

1

That is why classes should not rely on exposing state, aka fields.

Because there is no mechanism to notify an owner when some "other" object alters such a public variable.

If you want to be notified about such things, you make state private, but offer methods to update it. Then you can use the observer pattern on top of that so that any interested object gets notified about "property changes".

For debugging purposes, you can of course set a watch on variables. Which will use some sort of instrumentation so that assignments to variables actually become method invocations.

GhostCat
  • 137,827
  • 25
  • 176
  • 248
  • 1
    I *think* the OP is asking about debugging, not about the Observer pattern. If it is the latter, then his question is terrible. He uses local variables, not fields, and that basically makes an Observer pattern impossible. – markspace Jul 14 '18 at 18:46
  • 3
    The variables in his example aren't local! But I enhanced the question accordingly. Still, when you want to watch all variables you have a design issue. If you want to observe specific ones, the observer is a reasonable answer. – GhostCat Jul 14 '18 at 18:50
0

You could use AspectJ to intercept field assignments; in this way you can avoid cluttering your logic with logging code.

SomeClass.java:

public class SomeClass {

    private static int someVariableA;
    private static int someVariableB;
    private static int someVariableC;
    private static int someVariableD;

    public static void main(String[] args) {
        someVariableA = 0;
        someVariableB = 5;
        someVariableC = 8;
        someVariableD = someVariableA + someVariableB;
        someVariableD = 9;
    }
}

SomeAspect.java:

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;

@Aspect
public class SomeAspect {

    @After("set(static * SomeClass.*) && args(newValue)")
    public void afterFieldSet(JoinPoint joinPoint, Object newValue) {
        System.out.println(joinPoint.getSignature().getName() + " = " + newValue + " at " + joinPoint.getSourceLocation());
    }
}

The console output will be:

someVariableA = 0 at SomeClass.java:9
someVariableB = 5 at SomeClass.java:10
someVariableC = 8 at SomeClass.java:11
someVariableD = 5 at SomeClass.java:12
someVariableD = 9 at SomeClass.java:13

When you want to disable the logging, simply remove the aspect.

For sake of completeness, I also post here the pom.xml used for the build:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

    <modelVersion>4.0.0</modelVersion>
    <groupId>com.example</groupId>
    <artifactId>aspectj-example</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <properties>
        <maven.compiler.source>1.6</maven.compiler.source>
        <maven.compiler.target>1.6</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <build>
        <finalName>${project.artifactId}</finalName>
        <plugins>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>aspectj-maven-plugin</artifactId>
                <version>1.11</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>compile</goal>
                        </goals>
                        <configuration>
                        <complianceLevel>${maven.compiler.source}</complianceLevel>
                        <source>${maven.compiler.source}</source>
                        <target>${maven.compiler.target}</target>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <version>3.1.0</version>
                <configuration>
                    <archive>
                        <manifest>
                            <addClasspath>true</addClasspath>
                            <classpathPrefix>lib/</classpathPrefix>
                            <mainClass>SomeClass</mainClass>
                        </manifest>
                    </archive>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-dependency-plugin</artifactId>
                <version>3.1.1</version>
                <executions>
                    <execution>
                        <id>copy-dependencies</id>
                        <phase>prepare-package</phase>
                        <goals>
                            <goal>copy-dependencies</goal>
                        </goals>
                        <configuration>
                            <includeScope>runtime</includeScope>
                            <outputDirectory>${project.build.directory}/lib</outputDirectory>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

    <dependencies>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.8.13</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
            <version>1.8.13</version>
        </dependency>
    </dependencies>

</project>

To run this example, just launch mvn clean package and then java -jar target/aspectj-example.jar.

You can found more information about AspectJ on its website. I hope it helped.

Robert Hume
  • 1,129
  • 2
  • 14
  • 25