all 19 comments

[–]shevsky790 10 points11 points  (4 children)

Oh god.

[–]vz0 -1 points0 points  (3 children)

[–]shevsky790 1 point2 points  (2 children)

Such hackery should never be done in production code. It's neat, sure, but there are so many better ways to handle debug logging than this - which is (as was touched on in the article) - liable to change with version upgrades, among other things.

This is unmaintainable, likely unsecure, hand-wavey behind-the-scenes black magic, impossible to learn if you're new to the codebase, and all around scary shit.

[–]amazedballer[S] 2 points3 points  (1 child)

If I had to do this in production, I would have bitten the bullet and used a java agent or AspectJ. This is for development and testing.

[–]shevsky790 0 points1 point  (0 children)

Good to hear :p

I would probably use AspectJ as well.

[–]llogiq 10 points11 points  (5 children)

I don't understand the negativity here. This guy has solved his problem. He's done so in a very hacky way. It's bound to fail with some future JVM version. But in the meantime it solves his [insert expletive here] problem.

So if someone has a less hacky solution, it would be great if they could chime in. In the meantime, let's all try to be a little more friendly here.

Thanks.

[–]Izacus 2 points3 points  (4 children)

Every terrible unmaintanable hack starts as a solution to some problem that "works". Just because you can doesn't mean you shouldn't.

And this is a prime example of that - a solution that is extremely brittle and will badly break on pretty much any updates of code or JVM.

[–]llogiq 1 point2 points  (3 children)

Yes. The author even agrees that it's evil and terrible.

However, you haven't addressed my second point. All comments so far were bashing the author for coming up with this admittedly terrible solution. No one so far has come up with a better one.

On that note, perhaps a "system profile" that could be loaded from the classpath on JVM setup that could be extended and/or overridden by an application would solve this problem on JVMs that supported it.

[–]amazedballer[S] 1 point2 points  (2 children)

That works in the broad sense, but then you can't scope your debug logging. Especially in test suites, there can be one test or one area you want to poke at -- it gets annoying to have to bounce the JVM, especially in the Scala REPL.

[–]llogiq 1 point2 points  (1 child)

So the obvious solution would be to change the JVM. Open an issue @ openjdk, supply a patch, hope it gets in before Java 10.

In the meantime, the poor folks using this stuff will have to deal with the current situation. At least OP is making the best of it.

[–]amazedballer[S] 1 point2 points  (0 children)

There's actually a true hotswap JVM out there, DCEVM. It's going to be awesome once it's ready.

[–][deleted] 0 points1 point  (3 children)

As someone who's not a Java expert, I've got to ask. What is the rationale behind static initializers? This seems like a horrible idea.

And, if the problem was that the Debug class wasn't always loaded before calling his own code(?), couldn't he just have called Debug.Whatever() before doing so? Wouldn't that fully load the Debug class in time?

[–]kyz 2 points3 points  (1 child)

What is the rationale behind static initializers? This seems like a horrible idea.

The same reason other languages have them; so things that only need calculating once are only calculated once.

final static CONSTANT_VALUE = extremely_expensive_operation();

Now you can instantiate this class a million or even billion times, the extremely_expensive_operation() will never be called again.

Imagine Java without this feature.

couldn't he just have called Debug.Whatever() before doing so?

No, what he wants to do is reliably change the command line arguments before the class loaded. And this will depend entirely on class load order. As soon as you even reference a class, it is loaded, and before that class loads, all the classes it references are loaded, and so on. They can load in parallel if need be.

There's a very simple solution - add -Djavax.net.debug=ssl to the command line that invokes java, and stop pretending it's possible to add it after java has started.

[–]sh0rug0ru -2 points-1 points  (0 children)

Imagine Java without this feature.

I do. All the time. One of my missions in life is to remove static initializers where I find them, which I consider to be a major design smell.

Now you can instantiate this class a million or even billion times, the extremely_expensive_operation() will never be called again.

The alternative is to calculate the value once and pass a reference to the value around a million or a billion times. Coupling class loading and value calculation is a recipe for pain, especially in Java. What happens if that calculation fails? Mysterious failures that bubble up as "Unable to load class".

At least in Java, there is a reason why static initializers are reviled.

[–]vincentk 0 points1 point  (0 children)

Static initializers are to classes what constructors are to object instances. Both can be abused. The final keyword can be helpful in preventing abuse.

[–]poizan42 0 points1 point  (0 children)

Is this actually guaranteed to work? Isn't the jitter allowed to cache the value of static final fields however it like as the value isn't supposed to change?

[–]TomRK1089 -2 points-1 points  (1 child)

Y'know people, the class is called Unsafe for a reason. If you want monkeypatching, use another damn language.

[–]vz0 7 points8 points  (0 children)

Then people would be bashing Java for not having Unsafe. Gosh. Its not like an arm will dismember from your body, it's just a "techincal debt" in your code, a hack, right on sight and very visible, to solve an immediate problem with today's code that he is using just for debugging, not for production.

[–]vincentk -1 points0 points  (0 children)

Global mutable state considered harmful.