Accessing method and parameter history with Java - java

I'm currently working in a project in Liferay in which i'd like to be able to access my method and parameters these methods were given, in the history. This is done in case there is an exception being thrown in certain blocks of code.
I've already searched and it is easy to get the method name history (Thread.currentThread().getStackTrace();) but i'd like to also know what parameters were given to these methods.
For example:
public class A {
public static void main(String[] Args) {
try {
System.out.println(new B().someMethod(5));
} catch (Exception e) {
//GET HISTORY
}
}
}
public class B {
public int someMethod(int i) throws Exception {
i += 2;
throw new Exception("Expected Exception to Generate History Search");
return i;
}
}
Is it possible to learn how can i, in class A, when I catch the exception, all that data? And of so, how do I do that?

You can use Aspect Oriented Programming. Look at AspectJ for example.
The following aspect will trace all public method calls during your programs execution.
This can be fine-tuned to work with your own requirements. The pointcut can for example be adjusted to only take your own packages. The print statements can be changed into using some logging framework.
public aspect Trace {
pointcut publicMethodExecuted(): execution(public * *(..));
after(): publicMethodExecuted() {
System.out.printf("Enters on method: %s. \n", thisJoinPoint.getSignature());
Object[] arguments = thisJoinPoint.getArgs();
for (int i =0; i < arguments.length; i++){
Object argument = arguments[i];
if (argument != null){
System.out.printf("With argument of type %s and value %s. \n", argument.getClass().toString(), argument);
}
}
System.out.printf("Exits method: %s. \n", thisJoinPoint.getSignature());
}
}

You should consider using logging in your application.

You should definitely look in to logging in your application. If you want to avoid cluttering your code too much (I personally hate the constant log.debug(...) statements at start and end of each method), consider using Aspect Oriented Programming (google it for a whole host of good guides on it, or there's a decent aop guide using Spring here, just scroll down to the LoggingAspect), which will allow you to simply annotate methods or entire classes that you want logged.

Related

How to get rid of "Method parameters should be #State classes" in JMH when parameters come from another method?

I'm working on a maven project. The scenario is something like below...
class Test {
public void applyAll() {
....................
....................
Collection<Migratable> applicableUpdates = SomeOtherClass.getApplicableUpdates();
doUpdate(applicableUpdates);
}
#Benchmark
public void apply(Migratable m) {
....................
....................
}
private void doUpdate(Collection<Migratable> applicableUpdates) throws Exception {
for (Migratable m : applicableUpdates) {
try {
apply(m);
} catch (Exception e) {
logger.error("Falid to apply migration {}" + m, e);
throw e;
}
}
}
}
I need to compute how long it takes to execute each migration. Simply I need to compute the execution time of apply(Migratable m) method.
Now, when I build my project using "mvn clean install", build failed and it shows "Method parameters should be #State classes".
Here, parameter comes from another method doUpdate(Collection applicableUpdates) [see the scenario]. So how can I get rid of this error in given scenario?
There are quite a few problems in your setup here and it seems you haven't actually looked at the samples of JMH; and I strongly advise you to do that.
A few notes...
1) You #Benchmark method returns void - it should return something; otherwise use BlackHoles (this is in the samples).
2) If parameters comes from another method it means that method should be a #SetUp method (this is in the samples)
3) The error that you are seeing has to do with the fact that your Migratable is not actually a #State class (this is again in the samples!)
At this point I can't stress that enough - but look and understand the samples. It's not going to be easy, this is micro-benchmark and as much as JMH tries to make things easier for us by hiding all the very complicated code, it still requires us to conform to the rules that exist there.

Using monads in Springboot application to catch exceptions

So our project back-end is a Java 8 Springboot application, springboot allows you to do some stuff really easily. ex, request validation:
class ProjectRequestDto {
#NotNull(message = "{NotNull.DotProjectRequest.id}")
#NotEmpty(message = "{NotEmpty.DotProjectRequest.id}")
private String id;
}
When this constraint is not meet, spring (springboot?) actually throws a validation exception, as such, we catch it somewhere in the application and construct a 404 (Bad Request) response for our application.
Now, given this fact, we kinda followed the same philosophy throughout our application, that is, on a deeper layer of the application we might have something like:
class ProjectService throws NotFoundException {
DbProject getProject(String id) {
DbProject p = ... // some hibernate code
if(p == null) {
Throw new NotFoundException();
}
return p;
}
}
And again we catch this exception on a higher level, and construct another 404 for the client.
Now, this is causing a few problems:
The most important one: Our error tracing stops being useful, we cannot differentiate (easily) when the exception is important, because they happen ALL the time, so if the service suddenly starts throwing errors we would not notice until it is too late.
Big amount of useless logging, on login requests for example, user might mistyped his password, and we log this and as a minor point: our analytics cannot help us determine what we are actually doing wrong, we see a lot of 4xx's but that is what we expect.
Exceptions are costly, gathering the stack trace is a resource intensive task, minor point at this moment, as the service scales up with would become more of a problem.
I think the solution is quite clear, we need to make an architectural change to not make exceptions part of our normal data flow, however this is a big change and we are short on time, so we plan to migrate over time, yet the problem remains for the short term.
Now, to my actual question: when I asked one of our architects, he suggested the use of monads (as a temporal solution ofc), so we don't modify our architecture, but tackle the most contaminating endpoints (ex. wrong login) in the short term, however I'm struggling with the monad paradigm overall and even more in java, I really have no idea on how to apply it to our project, could you help me with this? some code snippets would be really good.
TL:DR: If you take a generic spring boot application that throws errors as a part of its data flow, how can you apply the monad pattern to avoid login unnecessary amount of data and temporarily fix this Error as part of data flow architecture.
The standard monadic approach to exception handling is essentially to wrap your result in a type that is either a successful result or an error. It's similar to the Optional type, though here you have an error value instead of an empty value.
In Java the simplest possible implementation is something like the following:
public interface Try<T> {
<U> Try<U> flatMap(Function<T, Try<U>> f);
class Success<T> implements Try<T> {
public final T value;
public Success(T value) {
this.value = value;
}
#Override
public <U> Try<U> flatMap(Function<T, Try<U>> f) {
return f.apply(value);
}
}
class Fail<T> implements Try<T> {
// Alternatively use Exception or Throwable instead of String.
public final String error;
public Fail(String error) {
this.error = error;
}
#Override
public <U> Try<U> flatMap(Function<T, Try<U>> f) {
return (Try<U>)this;
}
}
}
(with obvious implementations for equals, hashCode, toString)
Where you previously had operations that would either return a result of type T or throw an exception, they would return a result of Try<T> (which would either be a Success<T> or a Fail<T>), and would not throw, e.g.:
class Test {
public static void main(String[] args) {
Try<String> r = ratio(2.0, 3.0).flatMap(Test::asString);
}
static Try<Double> ratio(double a, double b) {
if (b == 0) {
return new Try.Fail<Double>("Divide by zero");
} else {
return new Try.Success<Double>(a / b);
}
}
static Try<String> asString(double d) {
if (Double.isNaN(d)) {
return new Try.Fail<String>("NaN");
} else {
return new Try.Success<String>(Double.toString(d));
}
}
}
I.e. instead of throwing an exception you return a Fail<T> value which wraps the error. You can then compose operations which might fail using the flatMap method. It should be clear that once an error occurs it will short-circuit any subsequent operations - in the above example if ratio returns a Fail then asString doesn't get called and the error propagates directly through to the final result r.
Taking your example, under this approach it would look like this:
class ProjectService throws NotFoundException {
Try<DbProject> getProject(String id) {
DbProject p = ... // some hibernate code
if(p == null) {
return new Try.Fail<DbProject>("Failed to create DbProject");
}
return new Try.Succeed<DbProject>(p);
}
}
The advantage over raw exceptions is it's a bit more composable and allows, for example, for you to map (e.g. Stream.map) a fail-able function over a collection of values and end up with a collection of Fails and Successes. If you were using exceptions then the first exception would fail the entire operation and you would lose all results.
One downside is that you have to use Try return types all the way down your call stack (somewhat like checked exceptions). Another is that since Java doesn't have built-in monad support (al la Haskell & Scala) then the flatMap'ing can get slightly verbose. For example something like:
try {
A a = f(x);
B b = g(a);
C c = h(b);
} catch (...
where f, g, h might throw, becomes instead:
Try<C> c = f(x).flatMap(a -> g(a))
.flatMap(b -> h(b));
You can generalise the above implementation by making the error type an generic parameter E (instead of String), so it then becomes Try<T, E>. whether this is useful depends on your requirements - I've never needed it.
I have a more fully-implemented version here, alternatively the Javaslang and FunctionalJava libraries offer their own variants.

How to dynamically generate a stack frame with debug log information

For better debugging, I would often like to have:
Exception
at com.example.blah.Something.method()
at com.example.blah.Xyz.otherMethod()
at com.example.hello.World.foo()
at com.example.debug.version_3_8_0.debug_info_something.Hah.method() // synthetic method
at com.example.x.A.wrappingMethod()
The debug stack frame as shown above would be dynamically generated, just like a java.lang.reflect.Proxy, except that I'd like to be in full control of the entire fully qualified method name that ends up on the proxy.
At the call site, I would do something silly and simple as this:
public void wrappingMethod() {
run("com.example.debug.version_3_8_0.debug_info_something.Hah.method()", () -> {
World.foo();
});
}
As you can see, the wrappingMethod() is a real method that ends up on the stack trace, Hah.method() is a dynamically generated method, whereas World.foo() is again a real method.
Yes, I know this pollutes the already deep deep stack traces. Don't worry about it. I have my reasons.
Is there a (simple) way to do this or something similar as the above?
No need for code generation to solve this problem:
static void run(String name, Runnable runnable) {
try {
runnable.run();
} catch (Throwable throwable) {
StackTraceElement[] stackTraceElements = throwable.getStackTrace();
StackTraceElement[] currentStackTrace = new Throwable().getStackTrace();
if (stackTraceElements != null && currentStackTrace != null) { // if disabled
int currentStackSize = currentStackStrace.length;
int currentFrame = stackTraceElements.length - currentStackSize - 1;
int methodIndex = name.lastIndexOf('.');
int argumentIndex = name.indexOf('(');
stackTraceElements[currentFrame] = new StackTraceElement(
name.substring(0, methodIndex),
name.substring(methodIndex + 1, argumentIndex),
null, // file name is optional
-1); // line number is optional
throwable.setStackTrace(stackTraceElements);
}
throw throwable;
}
}
With code generation, you could add a method with the name, redefine the call site within the method, unwind the frame and call the generated method but this would be much more work and would never be equally stable.
This strategy is a rather common approach in testing frameworks, we do it a lot in Mockito and also other utilities like JRebel do it to hide their magic by rewriting exception stack frames.
When Java 9 is used, it would be more efficient to do such manipulations using the Stack Walker API.

Correct helper method exception throwing

I have functions like
class Chainable {
public Chainable doStuff(String test) {
return doSomething(test, true);
}
public Chainable doStuff(String test, String test2) {
String toUse = test + test2;
return doSomething(toUse, false);
}
private Chainable doSomething(String test, boolean version) {
// do something
if (somethingBadHappened) {
throw SpecialException.generate();
}
return this;
}
}
SpecialException is an exception the user is supposed to see. The message of the exception purposely contains the method that threw this exception. The user would call doSomething("x") and if it fails it would show "Method 'doSomething' failed with the parameters: 'test = x | version = true'".
But the user doesn't care about the method doSomething(String, boolean) and its parameters. He used doStuff(String) and wants to see the message for that function.
So what I do is:
public Chainable doStuff(String test) {
try {
return doSomething(test, true);
} catch (SpecialException e) {
throw SpecialException.generate(e);
}
}
which sets e as the cause of the new exception and correctly shows "Method 'doStuff' failed with the parameters: 'test = x'" (the user doesn't see the stacktrace, but if I need to debug I can see what exactly happened).
Now, it works, but I have to repeat myself every time I write a new function that delegates its work to helper functions. The problem is, I don't know how I should use a helper function for this, since the SpecialException finds the method name depending on where it is generated...
Is there another, better way to do this?
Here's what you should do: show the stack trace to the user. You can then use
throw new SpecialException();
without any concerns about what method will appear.
As far as I can see, and as far as I know, this might be a nice situation to handle using aspect-oriented programming or AOP. In Java you can use AspectJ for that.
You would start by defining a "pointcut" - a specific moment in the execution of your code, for example a method invocation. Next, you would write an "advice", something that needs to be done when the pointcut is hit. You put those two together in an "aspect" and have them weaven into your bytecode during build.
In this case, you would need a pointcut that intercepts call to public methods on your Chainable, but the call should not be done from within Chainable:
pointcut publicChainableMethod() : target(Chainable)
&& call(public * *(..))
pointcut firstPublicChainableMethod() : target(Chainable)
&& call(* *(..))
&& !cflowbelow(publicChainableMethod());
The first pointcut defines any call to a public method on Chainable, the second pointcut defines a call to a method within Chainable, except it should not be called while being in the control flow of the first pointcut.
Next to that, you would need an advice that generates the new SpecialException for you:
after() throwing (SpecialException e): firstPublicChainableMethod() {
throw SpecialException.generate(e);
}
Disclaimer: I'm no AOP or AspectJ expert, so this approach might not work out-of-the-box.

String.format with lazy evaluation

I need something similar to String.format(...) method, but with lazy evaluation.
This lazyFormat method should return some object whose toString() method would then evaluate the format pattern.
I suspect that somebody has already done this. Is this available in any libararies?
I want to replace this (logger is log4j instance):
if(logger.isDebugEnabled() ) {
logger.debug(String.format("some texts %s with patterns %s", object1, object2));
}
with this:
logger.debug(lazyFormat("some texts %s with patterns %s", object1, object2));
I need lazyFormat to format string only if debug logging is enabled.
if you are looking for a "simple" solution:
public class LazyFormat {
public static void main(String[] args) {
Object o = lazyFormat("some texts %s with patterns %s", "looong string", "another loooong string");
System.out.println(o);
}
private static Object lazyFormat(final String s, final Object... o) {
return new Object() {
#Override
public String toString() {
return String.format(s,o);
}
};
}
}
outputs:
some texts looong string with
patterns another loooong string
you can of course add any isDebugEnabled() statement inside lazyFormat if you will.
It can be done by using parameter substitution in newest log4j 2.X version http://logging.apache.org/log4j/2.x/log4j-users-guide.pdf:
4.1.1.2 Parameter Substitution
Frequently the purpose of logging is to provide information about what is happening in the system, which
requires including information about the objects being manipulated. In
Log4j 1.x this could be accomplished by doing:
if (logger.isDebugEnabled()) {
logger.debug("Logging in user " + user.getName() + " with id " + user.getId());
}
Doing this repeatedly has the effect of making the
code feel like it is more about logging than the actual task at hand.
In addition, it results in the logging level being checked twice; once
on the call to isDebugEnabled and once on the debug method. A better
alternative would be:
logger.debug("Logging in user {} with id {}", user.getName(), user.getId());
With the code above the logging level
will only be checked once and the String construction will only occur
when debug logging is enabled.
if you are looking for lazy concatenation for the sake of efficient logging, take a look at Slf4J
this allows you to write:
LOGGER.debug("this is my long string {}", fatObject);
the string concatenation will only take place if the debug level is set.
IMPORTANT NOTE: It is strongly recommended all logging code be moved to use SLF4J (especially log4j 1.x). It protects you from being stuck with any sort of idiosyncratic issues (i.e. bugs) with specific logging implementations. Not only does it have "fixes" for well know backend implementation issues, it also works with newer faster implementations which have emerged over the years.
In direct response to your question, here what it would look like using SLF4J:
LOGGER.debug("some texts {} with patterns {}", object1, object2);
The most important bit of what you have provided is the fact you are passing two Object instances. The object1.toString() and the object2.toString() methods are not immediately evaluated. More importantly, the toString() methods are only evaluated if the data they return is actually going to be used; i.e. the real meaning of lazy evaluation.
I tried to think of a more general pattern I could use which didn't require my having to override toString() in tons of classes (and there are classes where I don't have access to do the override). I came up with a simple drop-in-place solution. Again, using SLF4J, I compose the string only if/when logging for the level is enabled. Here's my code:
class SimpleSfl4jLazyStringEvaluation {
private static final Logger LOGGER = LoggerFactory.getLogger(SimpleSfl4jLazyStringEvaluation.class);
...
public void someCodeSomewhereInTheClass() {
//all the code between here
LOGGER.debug(
"{}"
, new Object() {
#Override
public String toString() {
return "someExpensiveInternalState=" + getSomeExpensiveInternalState();
}
}
//and here can be turned into a one liner
);
}
private String getSomeExpensiveInternalState() {
//do expensive string generation/concatenation here
}
}
And to simplify into the one-liner, you can shorten the LOGGER line in someCodeSomewhereInTheClass() to be:
LOGGER.debug("{}", new Object(){#Override public String toString(){return "someExpensiveInternalState=" + getSomeExpensiveInternalState();}});
I have now refactored all my logging code to follow this simple model. It has tidied things up considerably. And now when I see any logging code which does not use this, I refactor the logging code to use this new pattern even if it is needed yet. That way, if/when a change is made later to need to add some "expensive" operation, the infrastructure boilerplate is already there simplifying the task to just adding the operation.
Building upon Andreas' answer, I can think of a couple of approaches to the issue of only performing the formatting if the Logger.isDebugEnabled returns true:
Option 1: Pass in a "do formatting" flag
One option is to have a method argument that tells whether or not to actually perform the formatting. A use case could be:
System.out.println(lazyFormat(true, "Hello, %s.", "Bob"));
System.out.println(lazyFormat(false, "Hello, %s.", "Dave"));
Where the output would be:
Hello, Bob.
null
The code for lazyFormat is:
private String lazyFormat(boolean format, final String s, final Object... o) {
if (format) {
return String.format(s, o);
}
else {
return null;
}
}
In this case, the String.format is only executed when the format flag is set to true, and if it is set to false it will return a null. This would stop the formatting of the logging message to occur and will just send some "dummy" info.
So a use case with the logger could be:
logger.debug(lazyFormat(logger.isDebugEnabled(), "Message: %s", someValue));
This method doesn't exactly fit the formatting that is asked for in the question.
Option 2: Check the Logger
Another approach is to ask the logger directly if it isDebugEnabled:
private static String lazyFormat(final String s, final Object... o) {
if (logger.isDebugEnabled()) {
return String.format(s, o);
}
else {
return null;
}
}
In this approach, it is expected that logger will be visible in the lazyFormat method. And the benefit of this approach is that the caller will not need to be checking the isDebugEnabled method when lazyFormat is called, so the typical use can be:
logger.debug(lazyFormat("Debug message is %s", someMessage));
You could wrap the Log4J logger instance inside your own Java5-compatible/String.format compatible class. Something like:
public class Log4jWrapper {
private final Logger inner;
private Log4jWrapper(Class<?> clazz) {
inner = Logger.getLogger(clazz);
}
public static Log4jWrapper getLogger(Class<?> clazz) {
return new Log4jWrapper(clazz);
}
public void trace(String format, Object... args) {
if(inner.isTraceEnabled()) {
inner.trace(String.format(format, args));
}
}
public void debug(String format, Object... args) {
if(inner.isDebugEnabled()) {
inner.debug(String.format(format, args));
}
}
public void warn(String format, Object... args) {
inner.warn(String.format(format, args));
}
public void error(String format, Object... args) {
inner.error(String.format(format, args));
}
public void fatal(String format, Object... args) {
inner.fatal(String.format(format, args));
}
}
To use the wrapper, change your logger field declaration to:
private final static Log4jWrapper logger = Log4jWrapper.getLogger(ClassUsingLogging.class);
The wrapper class would need a few extra methods, for example it does not currently handle of logging exceptions (ie logger.debug(message, exception)), but this shouldn't be hard to add.
Using the class would be almost identical to log4j, except strings are formatted:
logger.debug("User {0} is not authorized to access function {1}", user, accessFunction)
Introduced in Log4j 1.2.16 are two classes that will do this for you.
org.apache.log4j.LogMF which uses a java.text.MessageFormat for format you messages and org.apache.log4j.LogSF which uses the "SLF4J pattern syntax" and is said to be faster.
Here are examples:
LogSF.debug(log, "Processing request {}", req);
and
LogMF.debug(logger, "The {0} jumped over the moon {1} times", "cow", 5);
If you like the String.format Syntax better than the {0} Syntax and can use Java 8 / JDK 8 you can use lambdas / Suppliers:
logger.log(Level.FINER, () -> String.format("SomeOperation %s took %04dms to complete", name, duration));
()->... acts as a Supplier here and will be evaluated lazily.
Or you could write it as
debug(logger, "some texts %s with patterns %s", object1, object2);
with
public static void debug(Logger logger, String format, Object... args) {
if(logger.isDebugEnabled())
logger.debug(String.format("some texts %s with patterns %s", args));
}
You could defined a wrapper in order to call the String.format() only if needed.
See this question for a detailed code example.
The same question has also a variadic function example, as suggested in Andreas's answer.

Categories

Resources