MissingSuperCall in lint on android skips some situations - java

In my code, I have something like the following:
public class MyFragment extends Fragment {
#Override
public void onAttach(Activity aActivity) {
//super.onAttach(aActivity);
}
... some more code ...
}
It appears that even with the following configuration, lint misses that this class doesn't call the super.onAttach() method from within onAttach():
<?xml version="1.0" encoding="UTF-8"?>
<lint>
<!-- Disable the given check in this project -->
<issue id="MissingSuperCall" severity="fatal" />
</lint>
My question here is twofold:
Why is lint skipping this obvious error that should be marked as fatal?
If, as is my suspicion, that this isn't a method that lint checks (i.e. the onAttach() method of Fragment), then is there a way to get lint to flag this method as well (i.e. some deeper configuration, or, barring that, at the least an issue reporting mechanism for improving lint)?

1) Probably because you're listing it in the lint.xml file. This makes Android Lint ignore that particular error. Its mentioned here.
The lint.xml file
A configuration file that you can use to specify any lint checks that you want to exclude and to customize problem severity levels.
2) As far as flagging a method goes, you'll need to follow this. It tells you how to create a lint check for Android code. Thereafter, you could make use of the JavaScanner interface. Source can be found here. You can override the visitMethod API and visit instructions within the onAttach function. There you can check for a super.onAttach call. If not found, you can flag an error.

Related

How to efficiently add method name to Java logging message without typing it in manually?

In my Java application, I would like the logs to reflect the calling method name in the message. So that a the following code:
void foo(){
logger.info("some message");
}
would result with log message:
2020:10:10T10:10:10 thread class #foo some message
I am using Logback and SLF4J, and I understand that I can use message template.
To my understanding, this uses reflection and traveling up the call stack, and is a performance hit my team has had issues with in the past.
As an alternative, I looked into AOP, such as AsepectJ. As far as I can find, the calling context is not supplied in any of the AOP libraries. A simple before/after/wrap option won't reveal the identity of the method in which the call is made.
I'm looking for a way to inject a logging aspect using annotations. Something like:
#LogMethodName
class enhancedLoggingClass{
void foo(){
logger.info("some message");
}
}
And in some code/DSL I would write something like:
filter Methods with LogMethodName attribute OR inherited attribute from class
for each method:
find call to Logger(String s, *)
change to Logger(method.getName() + s, *)
In the past, in a C# 2.0 project a colleague tried out writing "shadow" code in which we could do anything. But this bypassed the tooling and made debugging not work, etc. So that was ditched.
Any suggestion are welcome.

Why does `public void append(LogEvent ev) have ev.getContextData().size() == 0`? (otherwise ev is fine)

logEvent.getContextData().size() == 0 and logEvent.getContextStack().size() == 0 but otherwise the attributes of the LogEvent are fine in:
public class MyAppender extends AbstractAppender {
.........
#override
public void append(LogEvent ev) {
ev.getDataContext().size(); // <=== how can this equals 0?
ev.getStackContext().size(); // <=== how can this equals 0?
....
}
}
I cannot figure-out why this is the case. Do I need to create an AbstractConverter? AbstractFilter? Is my log4j2.xml or maybe the plugin config wrong?
Based on our discussion in the comments, it looks like what you're actually after is the location information. In a custom appender, this can be obtained by walking the stack trace provided by LogEvent.getSource(). You should be aware that obtaining this information is expensive though (see the documentation).
Edit
As you've stated, location information can be very useful, so it's a shame that it's expensive to obtain. Unfortunately, there's nothing Log4J can do about that - it's down to java's architecture.
One cheaper method that's commonly used to obtain the class name at least, is to ensure that the Logger being logged to is named after the class in which it's used (see documentation here). Then, you can obtain the class name in an appender by calling LogEvent.getLoggerName(). Note, however, that if you're writing a general Appender implementation that may be reused across several projects, it would be bad practice to assume that this would always be the calling class's name. Instead, it should be interpreted as "the functional context that the logging call came from, as determined by the application".

Unit test: running programmatically a code that runs only at a real application instance

I am developing a plugin for PhpStorm, and in some point, it try to getContainingClass() from visited method. This method should return null when the class name is absent.
Just to make easier to explain, my visitPhpMethod() is like that:
final PhpClass methodClass = method.getContainingClass();
if (methodClass == null) {
return null;
}
My problem is justly to make the code-coverage of return null programmatically (from unit test) to proof that it is not a dead code. From a real instance of PhpStorm running my plugin I can reach this code when I just remove the class name like that:
Original code, that not access the return null:
class ThisIsMyClass { function x(){} }
Modified code without the class name, that access return null:
class { function x(){} }
But when I run the modified code from unit test, it give that:
class<error descr="Expected: class name"> </error>{ function x(){} }
And with that, my visitPhpMethod() is not triggered (while in real PhpStorm application it does). In this way, is impossible to coverage this part of code (but I like to do).
My best attempt: instead I relying on testHighlight() for that, I inputted with the functional code (that have the class name), then programatically I removed the class name (then the "expected class name" error don't happen anymore). Finally I run the visitPhpMethod() programmatically.
Unfortunatelly, the getContainingClass() instead of return null (that is what I expect to do), it just returns a PhpClass instance that don't have a name (and it should not works to me).
The code from this attempt could be seen here.
I tried to post the same problem on Intellij Community too, but without luck.
Okay, I found my issue.
On reality, the problem is not on getContaingClass(). It really doesn't returns null when called from visitPhpMethod(). I found my problem on another method that try to getNameIdentifier() from the containing class, in this case, it is really absent and I just try to return it from a #NotNull method.

Need help troubleshooting the stated error statement?

Sorry rather a newbie learning android studio where I downloaded a project here to get my hands dirty with coding a camera app uploaded to a server. But somehow I couldn't get it to work after I tried compiling it, with a error for this statement in the MainActivity.java file.
getActionBar().setBackgroundDrawable(new ColorDrawable(Color.parseColor(getResources().getString(R.color.action_bar))));
Error stated: Expected resource of type string less... (Ctrl+F1)
This inspection looks at Android API calls that have been annotated with various support annotations (such as RequiresPermission or UiThread) and flags any calls that are not using the API correctly as specified by the annotations. Examples of errors flagged by this inspection:
Passing the wrong type of resource integer (such as R.string) to an API that expects a different type (such as R.dimen).
Forgetting to invoke the overridden method (via super) in methods that require it
Calling a method that requires a permission without having declared that permission in the manifest
Passing a resource color reference to a method which expects an RGB integer value.
Thanks in advance.
try this
actionBar = getActionBar();
actionBar.setBackgroundDrawable(new ColorDrawable(getResources().getColor(R.color.action_bar)));
don't forget to set color names in your project's res/values/colors.xml file
xml file
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="action_bar">#fff</color> //write the color you want here
</resources>
ColorDrawable takes integer as parameter. You are trying to pass string.
getString(id) method returns string. getString this method is used read string from strings.xml as getString(R.string.yourid). You should define the colors.xml under /res/values/ folder. and you can read as follows: getColor(R.color.action_bar) . This method is deprecated. You should use
ContextCompat.getColor(yourcontext,R.color.action_bar)
getActionBar().setBackgroundDrawable(new ColorDrawable(Color.parseColor(ContextCompat.getColor(this,R.color.action_bar))));
You used this
getResources().getString(R.color.action_bar)
But R.color.action_bar is not a string value. Therefore the error Expected resource of type string
You have to use the correct method to get the color resource.
getResources().getColor(R.color.action_bar)
But that's deprecated, so use this
ContextCompat.getColor(MainActivity.this,R.color.action_bar)
Use getSupportActionBar() if you Activity is extends AppCompatActivity
and dont use Color.parseColor()
AppCompatActivity
getSupportActionBar().setBackgroundDrawable(new ColorDrawable(getResources().getColor(R.color.action_bar)));
Activity
getActionBar().setBackgroundDrawable(new ColorDrawable(getResources().getColor(R.color.action_bar)));

Overriding/Wrapping spring beans in java based config multiple times

I have a (web-)application that needs special configurations and/or extensions based on the customer using the application. I call these additions "plugins" and they are auto discovered by classpath scanning when the application starts. For extensions that is incredibly easy. Let's say I want to have a plugin which adds an API that prints "hello world" when the URL /myplugin/greet is called: I just create a #Controller annotated class with the according #RequestMapping, put this in a myplugin.jar, copy that on the classpath and that's it.
Problems come up when I want to change some defaults and especially if I want to do this multiple times. Let's say my core application has a config like this:
#Configuration
public class CoreConfiguration {
#Bean
public Set<String> availableModules() {
return Collections.singleton("core");
}
}
Now I have two plugins that don't know about each other (but they do know the CoreConfig), but they both want to add themselves to the list of available modules. How would I do that? If I only had a single plugin that wants to override the module list I could override the existing bean from CoreConfiguration, but with two plugins that becomes a problem. What I imagine is something like this:
#Configuration
public class FirstPluginConfiguration {
#Bean
public Set<String> availableModules(Set<String> availableModules) {
Set<String> extendedSet = new HashSet<>(availableModules);
extendedSet.add("FirstPlugin");
return extendedSet;
}
}
Of course a SecondPluginConfiguration would look nearly exactly like this, except that the Set is not extended by "FirstPlugin", but by "SecondPlugin". I tested it to check what would happen and spring will just never call the First/SecondPluginConfiguration "availableModules" methods but it does not show an error either.
Now of course in this case this could easily be solved by using a mutable Set in the CoreConfiguration and then autowiring and extending the set in the other configurations, but for example I also want to be able to add method interceptors to some beans. So for example I might have an interface CrashLogger which has a logCrash(Throwable t) method and in CoreConfiguration a ToFileCrashLogger is created that writes stack traces to files as the name suggests. Now a plugin could say that he also wants to get notified about crashes, for example the plugin wants to ADDITIONALLY send the stacktrace to someone by email. For that matter that plugin could wrap the CrashLogger configured by the CoreConfiguration and fire BOTH. A second plugin could wrap the wrapper again and do something totally different with the stacktrace and still call both of the other CrashLoggers.
The later does sound somewhat like AOP and if I'd just let ALL my beans be proxied (I did not test that) I could autowire them into my plugin configurations, cast them to org.springframework.aop.framework.Advised and then add advices that manipulate behaviour. However it does seem like a huge overkill to generate proxies for each and everyone of my beans just so that that plugin can potentially add one or two advices one one or two beans.

Categories

Resources