Reflection much slower than normal - java

I am currently working on a Java project in which I am trying to learn the ins and outs. In previous projects, I have used Java reflection in order to create a toString() by calling each getter in an object and parsing it to display the value. This method has been a helpful, clean, and dynamic way to display the data.
Below is a heavily simplified version of my code:
private static String objectToString(Object o) {
LOGGER.debug("entering ObjectStringUtils::objectToString()");
....
Class<?> oClass = o.getClass();
String className = oClass.getName();
Method[] methods = oClass.getMethods();
for (Method m : methods) {
if ([method is a getter]) {
String methodName;
Object value;
try {
methodName= m.getName();
LOGGER.debug("Invoking " + className + "::" + methodName);
Object value = m.invoke(o);
LOGGER.debug("Invoked " + className + "::" + methodName);
} catch (Exception e) {
e.printStackTrace();
value = null;
}
LOGGER.debug(methodName+ " -> " + value);
}
}
}
This produces logger output which looks like this:
14:47:49,478 [] DEBUG ObjectStringUtils:? - Invoking org.hibernate.impl.SessionImpl::isOpen
14:47:49,613 [] DEBUG ObjectStringUtils:? - Invoked org.hibernate.impl.SessionImpl::isOpen
14:47:49,613 [] DEBUG ObjectStringUtils:? - isOpen -> true
Notice that it took Java 139 milliseconds to call the function. It takes this long to perform the reflection in any method in any class, even if the method is only a standard getter which performs no logic other than to return a value. This means that it takes far too long to perform the operation when there are multiple nested values involved. When I used reflection previously on WebSphere 7, it took a tiny fraction of this long to perform the operation.
So my question is: why is it taking so long to process? I understand that reflection is slower, but it shouldn't be on the magnitude of 140 milliseconds to call a getter. Is this an artifact of the way it takes WebLogic a long time to call a function, or the fact that line numbers appear to be stripped from the .class files? So far, I don't have any idea.

When you benchmark a piece of code, you must time the same operation several times, otherwise the test is meaningless - it could have been caused by garbage collection or by another process running on the same computer.

When Methods are cached - e.g. used in a framework and oClass.getMethods() is called only once, reflective call to a method is only ~2-3 slower than a direct method call. I think that oClass.getMethods() must be the slowest part in your reflection, not the method invocation.
So may be it's SessionImpl::isOpen which is slow by itself? I.e. it checks if it's still connected, or does any slow interaction with the database? 139 ms is very slow even for a DB transaction, so this also could happen because of some errors occuring during this call.

Related

How compareAndSet works internally in redis

spring-data-redis module contains RedisAtomicLong class.
In this class you can see
public boolean compareAndSet(long expect, long update) {
return generalOps.execute(new SessionCallback<Boolean>() {
#Override
#SuppressWarnings("unchecked")
public Boolean execute(RedisOperations operations) {
for (;;) {
operations.watch(Collections.singleton(key));
if (expect == get()) {
generalOps.multi();
set(update);
if (operations.exec() != null) {
return true;
}
}
{
return false;
}
}
}
});
}
My question is why it works?
generalOps.multi() starts transaction after get() is invoked. It means that there is possibility that two different thread (or even client) can change value and both of them will succeed.
Is operations.watch prevent it somehow? JavaDoc doesn't explain purpose of this method.
PS: Minor question: why for (;;)? There is always one iteration.
Q: Is operations.watch prevent it somehow?
YES.
Quoting from Redis documentation about transaction:
WATCH is used to provide a check-and-set (CAS) behavior to Redis transactions.
WATCHed keys are monitored in order to detect changes against them. If at least one watched key is modified before the EXEC command, the whole transaction aborts, and EXEC returns a Null reply to notify that the transaction failed.
You can learn more about Redis transaction from that documentation.
Q: why for (;;)? There is always one iteration.
It seems the code you've posted is very old. From Google's cache of this url, I saw the code you provided which is dated back to Oct 15th, 2012!
Latest codes look much different:
compareAndSet method
CompareAndSet class
Is operations.watch prevent it somehow?
YES. After watching a key, if the key has been modified before transaction finishes, EXEC will fail. So if EXEC successes, the value is guaranteed to be unchanged by others.
why for (;;)? There is always one iteration.
In your case, it seems the infinite loop is redundant.
However, if you want to implement a check-and-set operation to modify the value with the old value, the infinite loop is necessary. Check this example from redis doc:
WATCH mykey
val = GET mykey
val = val + 1
MULTI
SET mykey $val
EXEC
Since EXEC might fail, you need to retry the whole process in a loop until it successes.
RedisAtomicLong.compareAndSet implementation is not optimal since it requires 5 requests to Redis
Redisson - Redis Java client provides more efficient implementation.
org.redisson.RedissonAtomicLong#compareAndSetAsync method implemented using atomic EVAL-script:
"local currValue = redis.call('get', KEYS[1]); "
+ "if currValue == ARGV[1] "
+ "or (tonumber(ARGV[1]) == 0 and currValue == false) then "
+ "redis.call('set', KEYS[1], ARGV[2]); "
+ "return 1 "
+ "else "
+ "return 0 "
+ "end",
This script requires only single request to Redis.
Usage example:
RAtomicLong atomicLong = redisson.getAtomicLong("myAtomicLong");
atomicLong.compareAndSet(1L, 2L);

SonarQube: Invoke method(s) only conditionally

The following part of code raises a major bug at SonarQube :
"Invoke method(s) only conditionally."
How am I supposed to fix this?
if(us != null){
logger.info("Log this: {}", us.toString());
}
The call to us.toString() is redundant, toString() method will be called regardless the configured log level. You should pass only us as an argument to info without an if statement.
logger.info("Log this: {}", us);
As stated at the comments of the question, another working answer is:
if(logger.isInfoEnabled() && us != null){
logger.info("Log this: {}", us.toString());
}
You can just ignore this but it might be good to handle this scenario if possible, It would help us to handle and cutoff unnecessary computations.
One thing what it suggests here is to check if the Log Level that you are going to use is enabled or not.
if(logger.isInfoEnabled() && us != null){
// this inner code will only get executed if the above is true
logger.info("Log this: {}", us.toString());
}
Imagine having a complex task running inside, it would be a waste of time to do that if you are not going to log it anyways, if the log level is disabled. Logger will internally check that for you but doing it now before invoking the .info() will save you some cycles.
Passing message arguments that require further evaluation into a Guava com.google.common.base.Preconditions check can result in a performance penalty. That's because whether or not they're needed, each argument must be resolved before the method is actually called.
Similarly, passing concatenated strings into a logging method can also incur a needless performance hit because the concatenation will be performed every time the method is called, whether or not the log level is low enough to show the message.
Instead, you should structure your code to pass static or pre-computed values into Preconditions conditions check and logging calls.
Specifically, the built-in string formatting should be used instead of a string concatenation, and if the message is the result of a method call, then Preconditions should be skipped altogether, and the relevant exception should be conditionally thrown instead.
Noncompliant Code Example
logger.log(Level.DEBUG, "Something went wrong: " + message);
// Noncompliant; string concatenation performed even when log level too high to show DEBUG messages
logger.fine("An exception occurred with message: " + message);
// Noncompliant
LOG.error("Unable to open file " + csvPath, e); // Noncompliant
Preconditions.checkState(a > 0, "Arg must be positive, but got " + a);
// Noncompliant. String concatenation performed even when a > 0
Preconditions.checkState(condition, formatMessage()); // Noncompliant. formatMessage() invoked regardless of condition
Preconditions.checkState(condition, "message: %s", formatMessage());
// Noncompliant
Compliant Solution
logger.log(Level.SEVERE, "Something went wrong: {0} ", message);
// String formatting only applied if needed
logger.fine("An exception occurred with message: {}", message);
// SLF4J, Log4j
logger.log(Level.SEVERE, () -> "Something went wrong: " + message);
// since Java 8, we can use Supplier , which will be evaluated lazily
LOG.error("Unable to open file {0}", csvPath, e);
if (LOG.isDebugEnabled() {
LOG.debug("Unable to open file " + csvPath, e);
// this is compliant, because it will not evaluate if log level is above debug.
}
Preconditions.checkState(arg > 0, "Arg must be positive, but got %d", a); // String formatting only applied if needed
if (!condition) {
throw new IllegalStateException(formatMessage()); /
/ formatMessage() only invoked conditionally
}
if (!condition) {
throw new IllegalStateException("message: " + formatMessage());
}
Exceptions
catch blocks are ignored because the performance penalty is unimportant on exceptional paths (catch block should not be a part of standard program flow). Getters are ignored as well as methods called on annotations which can be considered as getters. This rule accounts for explicit test-level testing with SLF4J methods isXXXEnabled and ignores the bodies of such if statements.
It's related to performance issues. They recomend just putting a pure String or a final variable defined previously.
final var message = "Log this: " + us.toString();
logger.info(message);
https://sonarcloud.io/organizations/default/rules?languages=java&open=java%3AS2629&q=S2629
Short easy answer: just delete the .toString from your code since the formatter will take care of changing it to String for you.

Is Antlr the right tool to trace Java method calls with parameter names and values, and return result?

I want to print out Java method calls with names and values of parameters, and return results.
I don't want to manually add the trace statements, especially when the code is in a 3rd party library. I need to understand the interactions with the library, especially when callbacks are used.
I have tried to use a wrapper, but ran into problems, so subclassing is better. (i.e. either wrappedObject.methodA() or super.methodA() calls)
It's a pain to write this code especially when there are lots of methods.
I wish Java can do this automatically, since it has everything to make this possible easily.
What is the best way to do this? Substituting objects with the wrapper or subclass is a compromise.
So, the next step is to add the tracing code to the wrapper or subclass. I thought of writing a parser to generate the code.
I have used yacc & lex before, and just found out about Antlr.
Is Antlr the right tool to do this? How would I do it please? I haven't used Antlr before, but have seen it around.
Thanks.
Here's what I want to do -
// 3rdParty library under investigation, with evolving versions
import com.3rdParty.lib.Service;
import com.3rdParty.lib.Callback;
MyExistingClass {
Service service = new Service();
// Need to understand 3rd party library service and callback interactions
// Also need to write my own callbacks using 3rd party interface
if (traceMethod1) {
service.doSomething(param1, new CallbackWrapper(), param3);
}
else if (traceMethod2) {
service.doSomething(param1, new CallbackSubclass(), param3);
}
else {
// Original code
// Service calls Callback methods
service.doSomething(param1, new Callback(), param3);
}
}
--------------------------------------------------------------------------------
// 3rd Party code - Service calls Callback methods
package com.3rdParty.lib;
public Callback extends SomeBaseClass {
public void methodA(int code, String action, SomeClass data) {
// do method A stuff
}
public String methodB(String name, boolean flag) {
// do method B stuff
return result;
}
...etc.
}
--------------------------------------------------------------------------------
// Wrapper class - traceMethod1
package com.my.package;
import com.3rdParty.lib.Callback;
public CallbackWrapper implements SomeCallbackInterface {
Callback cb = new Callback();
public void methodA(int code, String action, SomeClass data) {
logger.debug("CallbackWrapper.methodA() called");
logger.debug(" code = " + code);
logger.debug(" action = " + action);
logger.debug(" data = " + data);
cb.methodA(code, action, data);
logger.debug("CallbackWrapper.methodA() returns");
}
public String methodB(String name, boolean flag) {
logger.debug("CallbackWrapper.methodB() called");
logger.debug(" name = " + name);
logger.debug(" flag = " + flag);
String result = cb.methodB(name, flag);
logger.debug("CallbackWrapper.methodB() returns result = " + result);
return result;
}
...etc.
}
--------------------------------------------------------------------------------
// Subclass - traceMethod2
package com.my.package;
import com.3rdParty.lib.Callback;
public CallbackSubclass extends Callback {
public void methodA(int code, String action, SomeClass data) {
logger.debug("CallbackSubclass.methodA() called");
logger.debug(" code = " + code);
logger.debug(" action = " + action);
logger.debug(" data = " + data);
super.methodA(code, action, data);
logger.debug("CallbackSubclass.methodA() returns");
}
public String methodB(String name, boolean flag) {
logger.debug("CallbackSubclass.methodB() called");
logger.debug(" name = " + name);
logger.debug(" flag = " + flag);
String result = super.methodB(name, flag);
logger.debug("CallbackSubclass.methodB() returns result = " + result);
return result;
}
...etc.
}
The easiest way to do this sort of thing in Java is to work with byte code rather than source code. Using BCEL (https://commons.apache.org/proper/commons-bcel/) or ASM (http://asm.ow2.org/), you can dynamically create and load modified versions of existing classes, or even entirely new classes generated from scratch.
This is still not easy, but it's much easier than trying to do source code translation.
For your particular problem of tracing method calls, you can make a custom ClassLoader that automatically instruments every method in every class it loads with custom tracing code.
ANTLR is not the right tool. While you can get Java grammars for ANTLR that will build ASTs, ANTLR won't help you, much, trying to modify the ASTs or regenerate compilable source text.
What you need is a Program Transformation System (PTS). These are tools that parse source code, build ASTs, provide you with means to modify these ASTs generally with source to source transformations, and can regenerate compilable source text from the modified tree.
The source-to-source transformations for a PTS are usually written in terms of the language-to-be-transformed syntax (in this case, java):
if you see *this*, replace it by *that* if some *condition*
Our DMS Software Reengineering Toolkit is such a PTS with an available Java front end.
What you want to do is very much like instrumenting code; just modify the victim methods to make them do your desired tracing. See Branch Coverage Made Easy for examples of how we implemented an instrumentation tool for Java using such source-to-source rewrites.
Alternatively, you could write rules that replicated the victim classes and methods as subclasses with the tracing wired in as you have suggested. The instrumentation is probably easier than copying everything. [Of course, when you are writing transformation rules, you really don't care how much code changes since in your case you are going to throw it away after you are done with it; you care how much effort it is to write the rules]
See DMS Rewrite Rules for a a detailed discussion of what such rules really look like, and worked example of rewrite rules that make changes to source code.
Others suggest doing transformation on the compiled byte code. Yes, that works for the same reason that a PTS system works, but you get to do the code hacking by hand and the transforms, written as a pile of procedural goo operating on JVM instructions are not readable by mere humans. In the absence of an alternative, I understand people take this approach. My main point is there are alternatives.

Is Log4j isDebugEnabled() necessary before using logger.debug()? [duplicate]

This question already has answers here:
Is there a need to do a if(log.isDebugEnabled()) { ... } check? [duplicate]
(5 answers)
Closed 7 years ago.
When I was going through some code, I noticed the use of logger as follows,
if(logger.isDebugEnabled())
logger.debug("Something..");
But in some codes, I observed like this.
logger.debug("Something..");
When I looked at the source of log4j, in the debug() method of Logger itself if(logger.isDebugEnabled()) was checked. Then why do we need this unnecessary overhead if(logger.isDebugEnabled())??
It's useful when the String your passing to logger.debug(...) takes time to evaluate, in that case you can skip this evaluation if debug is not enabled.
if(logger.isDebugEnabled()) {
logger.debug("The meaning of life is " + calculateMeaningOfLife());
}
IMO this makes the code a lot less readable so it should only be used when there's a significant performance improvement.
isDebugEnabled is typically used to avoid unnecessary String concatination, eg this call
logger.debug("Line number = " + n);
first invokes Strings concatination then debug() and only then Logger detects that debug is not enabled and simply returns. This may significantly affect app performance.
This problem is solved in SLF4J which has formatted logging methods like this
public void debug(String format, Object arg);
Java must first resolve the string parameter passed to the debug method before it can call it.
logger.debug("Something.. var1=" + variable1 + " var2=" + variable2);
The above code will result in multiple String objects being created as each + creates another String so you'll have about 5 or more objects created before calling the method.
Debugging will mostly not be enabled so it's more efficient to check if debugging is enabled than to resolve the parameters all the time.
The statement:
if(log.isDebugEnabled()){
Is used just for performance reasons. It's use is optional since it is called by the log method internally.
But now you ask if this check is made internally, so why should I use it? It's very simple: if you log something as simple as this:
log.debug("ResultSet rs is retrieved from OracleTypes");
Then you don't need to do any check. If you compose a string to log using the append operator (+) like this:
log.debug("[" + System.getTimeInMillis() + "] ResultSet rs is retrieved from OracleTypes");
In this case you should check if the log is enabled or not, because if it isn't, even if the log is not made, the string composition is. And I must remind you that the use of operator "+" to concatenate strings is very inefficient.
SLF4J implementation (checked on version 1.7.10) calls isDebugEnabled() in some methods like:
public void debug(String format, Object... arguments) {
if(this.log.isDebugEnabled()) {
FormattingTuple ft = MessageFormatter.arrayFormat(format, arguments);
this.log.debug(ft.getMessage(), ft.getThrowable());
}
}
but there are also method overloads which doesn't internally check whether given loggin level is enabled, like in:
public void debug(String msg, Throwable t) {
this.log.debug(msg, t);
}
Another thing is that Logger implementation can be changed so if you want to be always sure your logger is called according to it's logging level, then you might want to consider using isDebugEnabled() method.

caching in java

guys
I am implementing a simple example of 2 level cache in java:
1st level is memeory
2nd - filesystem
I am new in java and I do this just for understanding caching in java.
And sorry for my English, this language is not native for me :)
I have completed 1st level by using LinkedHashMap class and removeEldestEntry method and it is looks like this:
import java.util.*;
public class level1 {
private static final int max_cache = 50;
private Map cache = new LinkedHashMap(max_cache, .75F, true) {
protected boolean removeEldestEntry(Map.Entry eldest) {
return size() > max_cache;
}
};
public level1() {
for (int i = 1; i < 52; i++) {
String string = String.valueOf(i);
cache.put(string, string);
System.out.println("\rCache size = " + cache.size() +
"\tRecent value = " + i +
" \tLast value = " +
cache.get(string) + "\tValues in cache=" +
cache.values());
}
}
Now, I am going to code my 2nd level. What code, methods I should write to implement this tasks:
1) When the 1st level cache is full, the value shouldn't be removed by removeEldestEntry but it should be moved to 2nd level (to file)
2) When the new values are added to 1st level, firstly this value should be checked in file (2nd level) and if it exists it should be moved from 2nd to 1st level.
And I tried to use LRUMap to upgrade my 1st level but the compiler couldn't find class LRUMap in library, what's the problem? Maybe special syntax needed?
You can either use the built in java serialization mechanism and just send your stuff to file by wrapping FileOutputStrem with DataOutputStream and then calling writeObjet().
This method is simple but not flexible enough. for example you will fail to read old cache from file if your classes changed.
You can use serialization to xml, e.g. JaxB or XStream. I used XStream in past and it worked just fine. You can easily store any collection in file and the restore it.
Obviously you can store stuff in DB but it is more complicated.
A remark is that you are not getting thread safety under consideration for your cache! By default LinkedHashMap is not thread-safe and you would need to synchronize your access to it. Even better you could use ConcurrentHashMap which deals with synchronization internally being able to handle by default 16 separate threads (you can increase this number via one of its constructors).
I don't know your exact requirements or how complicated you want this to be but have you looked at existing cache implementations like the ehcache library?

Categories

Resources