DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports Events Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones AWS Cloud
by AWS Developer Relations
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones
AWS Cloud
by AWS Developer Relations

Injecting Better Logging Into a Binary .class Using Javassist

Jakub Holý user avatar by
Jakub Holý
·
May. 23, 10 · Interview
Like (0)
Save
Tweet
Share
10.06K Views

Join the DZone community and get the full member experience.

Join For Free

have you ever been struck by a completely useless exception message somewhere from the depths of a 3rd party application or library you had to use in your code? have you ever wanted the bloody nameless programmer to have written a truly informative and helpful error message so that you wouldn’t need to spend hours trying to figure out what was the problem that would have been easily discovered if only more context information available at the moment when the exception occured was included in its error message? have you wondered how only you could inject the necessary logging into the spot? read on to get the answer.

recently i was testing my extension to saba, a monstrous j2ee learning management system, and got an exception from a saba class saying that the expected and actual data types of a custom attribute don’t match.  the problem was that i had no idea which one of the 10s of custom attributes could be the cause and i even wasn’t sure which object’s attributes i should check. it would be so much easier if the "nameless bloody saba programmer" (no offense :-) ) included the attribute’s name and preferably also its actual & expected data types and the actual and new values. how could i insert there logging of these properties? needless to say that i had to use java 1.4 (no agents…) and couldn’t afford more than modifying this single class file (i.e. no additional libraries etc.) because the changes i could do to the development environment where the application ran were limited.

of course the easiest would have been to decomile the class, add the loging before the exception is thrown, recompile it and replace it on the server. but not only is decompiling illegal here, it also sometimes simply doesn’t work. fortunatelly there is another solution – jboss javassist is a byte code manipulation library that supports not only runtime manipulation but also post-comilation time manipulation, i.e. you can modify and save the class and use it to replace the original file. there are quite a few byte code manipulation libraries but javassist has the great advantage that you don’t need to know much about bytecode, you can simply pass a string with java statements that should be inserted before/after/… method call or into a new catch statement. there is a nice tutorial that describes it (see part 4.1, inserting source text at the beginning/end of a method body):

addcatch() inserts a code fragment into a method body so that the code fragment is executed when the method body
throws an exception and the control returns to the caller. in the source text representing the inserted code fragment,
the exception value is referred to with the special variable $e.


for example, this program:

classpool pool = classpool.getdefault();
ctclass compiledclass = pool.get("mypackage.myclass");
ctmethod m = compiledclass.getdeclaredmethod("myexceptionthrowingmethod");
ctclass etype = classpool.getdefault().get("java.io.ioexception");
m.addcatch("{ system.out.println($e); throw $e; }", etype);

translates the method body represented by m into something like this:

try {
the original method body
}
catch (java.io.ioexception e) {
system.out.println(e);
throw e;
}


note that the inserted code fragment must end with a throw or return statement.

you can use $e to access the exception, $0 to access "this", $1 to access the 1st parameter of the method etc. at the end you just call compiledclass.writefile(); and use the modified mypackage/myclass.class to replace the original class in the application.

lovely, isn’t it?

from http://theholyjava.wordpress.com/2008/10/02/injecting-better-logging-into-a-bi/

Javassist

Opinions expressed by DZone contributors are their own.

Popular on DZone

  • How To Best Use Java Records as DTOs in Spring Boot 3
  • Strategies for Kubernetes Cluster Administrators: Understanding Pod Scheduling
  • Test Execution Tutorial: A Comprehensive Guide With Examples and Best Practices
  • Asynchronous Messaging Service

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com
  • +1 (919) 678-0300

Let's be friends: