Android NullPointerException - Debugging a specific line - java

If I have a line like this:
var.getSomething().getSomethingElse().setNewValue(stuff.getValue().getWhatever());
If that line creates a NullPointerException, is there any way of finding out which method is returning a null value?
I believe I was able to split the line at every dot and get the exception showing which line was failing. But I can't get that to work anymore (maybe I remember incorrectly).
Is the only good debugging possibility to write it like this?
a = var.getSomething();
b = a.getSomehingElse();
c = stuff.getValue();
d = c.getWhatever();
b.setNewValue(d);
With this I should be able to easily see where the exception happens. But it feels inefficient and ugly to write this way.
I use Android Studio. Used Eclipse before but moved to Android Studio some time ago.

You might want to put every part into "Watches":
But I'm pretty sure that both Eclipse and Android Studio would let you inspect the content by just a selection of the part you' re interested in (if you are in debug mode)

The best I can advice for you is to use #Nullable and #NonNull annotations for all methods with return values. It would not help you to get line where null pointer is but would help to prevent such situations in future.
So if method may return null and you have it in call sequence you will get warning from Android Studio about this. In this case it is better to break sequence and check for null.
For example:
private static class Seq {
private final Random rand = new Random();
#NonNull
public Seq nonNull() {
return new Seq();
}
#Nullable
public Seq nullable() {
return rand.nextInt() % 100 > 50 ? new Seq() : null;
}
}
If you write new Seq().nonNull().nonNull().nullable().nonNull(); you will get warning from IDE:
Method invocation `new Seq().nonNull().nonNull().nullable().nonNull()` may produce 'java.lang.NullPointerException'
The best solution in this case is to change code like so:
Seq seq = new Seq().nonNull().nonNull().nullable();
if (seq != null) {
seq.nonNull();
}
Don't forget to add it into Gradle build script
compile 'com.android.support:support-annotations:22.+'

I am not positive on the way you are doing it. This makes your code tightly coupled and not unit testable.
var.getSomething().getSomethingElse().setNewValue(stuff.getValue().getWhatever());
Instead do something like
var.getSomething();
that get something internally does whatever you are doing as a part of
getSomethingElse().setNewValue(stuff.getValue().getWhatever())
In the same way getSomethingElse() should perform whatever you are doing as a part of
setNewValue(stuff.getValue().getWhatever())

Related

Trouble splitting an array in #PostConstruct Method of my Kafka SpringBoot Application

I'm creating a Kafka Springboot listener that tracks the state of an object. I have the kafka portion working and am able to listen to the topics. I am using a Tree map to map a string key that is the topic to an object. The topic name actually contains some information that I want to use to initialize the object. My question is this ( I apologize, I'm not very familiar with SpringBoot).
In my Post Construct method, I have a string array that is coming in called locoTopics. I've verified that strings are coming in and they are of the form "ignore.ignore.mark.id". The issue I'm running into is that when I try to split the string in the Post Construct method it appears to return null even though the string definitely contains the "." expression. I say it appears, because the program appears to jump forward and skip several lines of code. To be precise, when I debug. It appears to go from the "String [] locoArray = locoTopics[i].split("\.");" line to my Object constructor immediately and skip all the steps in between. Then it appears to jump in and out of the loop. I'm very confused why this is. Is this something related to SpringBoot that is happening or am I missing something in my code? Any help would be greatly appreciated.
public class InitTrackerReceiver {
// instance variables
Map mapr = new TreeMap<String, Locomotive>();
String[] locoTopics;
public List<String> m_failureCodes;
// Moved Functionality to get loco ids into separate class, Locomotive IDs now
// gets locoids
#Autowired
public LocomotiveIDs locomotiveIDs;
//This is where loco objects will be instantiated
#PostConstruct
public void initializeLocomotives() {
// grab loco topic strings and separate into a string array
locoTopics = locomotiveIDs.getLocoString();
// Go through the loco topics from application.properties and create a Loco
// object with that string as identifier
for (int i = 0; i < locoTopics.length; i++) {
String [] locoArray = locoTopics[i].split("\\.");
String markString = locoArray[2];
String scacString = "name";
String idString = locoArray[3];
mapr.put(locoTopics[i], new Locomotive(locoTopics[i], markString, scacString, idString));
}
}
#Value("#{'${failure.init.messagefields}'.split(',')}")
List<String> typesToFail;
I figured I'd go ahead and follow up with the answer. I have no clue how this happened, but the code that was in Eclipse that was in the debugger was not the same code that was running. I don't know if this was a bug in EGIT or Eclipse. It became apparent when I ran a Maven clean and my project would no longer launch. Whenever I tried to debug, it would launch and say that it couldn't find the main class, which was my Spring application launch class. I did a Maven Build and that seemed to get everything in sync. Then the code started working as expected.

CDT API: Issues looking up values using the IIndex

Part of a program I am working on requires looking up preprocessor macros by name, and then getting their values. I opted to use the CDT Indexer API. In order to make sure I am on the right track, I wrote a test method that does nothing but create a simple C file and confirm that it can find certain symbols in the index. However, I failed to get that test to run properly. Attempting to use IIndex.findBindings(char[], IndexFilter, IProgressMonitor) returns empty arrays for symbols that I know exist in the AST because they are part of the example file in the test method.
I can't post the exact test method because I use some custom classes and it would be overkill to post all of them, so I will just post the important code. First, my example file:
final String exampleCode =
"#define HEAVY 20\n" +
"#define TEST 5\n" +
"void function() { }\n" +
"int main() { return 0; }\n";
IFile exampleFile = testProject.getFile("findCodeFromIndex.c");
exampleFile.create(new ByteArrayInputStream(exampleCode.getBytes("UTF-8") ), true, null);
I have a custom class that automatically gets the IASTTranslationUnit from that file. The translation unit is fine (I can see the nodes making up everything except the macros). I get the index from that AST, and the code I use to look up in the index is
try {
index.acquireReadLock();
returnBinding = index.findBindings(name.toCharArray(), IndexFilter.ALL, null);
... catch stuff...
} finally {
index.releaseReadLock();
}
Where 'name' is going to be either "HEAVY", "TEST", or "function". None of them are found, despite existing in the example test c file.
I am guessing that the issue is the index is not rebuilt, which causes findBindings to return an empty array even if I know the given variable name exists in the AST.
My current attempt to start up the indexer looks like this:
final ICProject cProject = CoreModel.getDefault().getCModel().getCProject(testProject.getName());
CCorePlugin.getIndexManager().reindex(cProject);
CCorePlugin.getIndexManager().joinIndexer(IIndexManager.FOREVER, new NullProgressMonitor() );
Question Breakdown:
1) Is my method for searching the index sound?
2) If the issue is the index needing to be rebuilt, how should I properly force the index to be up to date for my test methods? Otherwise, what exactly is the reason I am not resolving the bindings for macros/functions I know exist?
I solved my own issue so I will post it here. I was correct in my comment that the lack of the project being a proper C project hindered the Indexer from working properly, however I also discovered I had to use a different method in the indexer to get the macros I needed.
Setting up the test enviornment:
Here is the code I have that creates a basic C project. The only purpose it serves is to allow the indexer to work for test methods. Still, it is large:
public static IProject createBareCProject(String name) throws Exception {
IProject bareProjectHandle = ResourcesPlugin.getWorkspace().getRoot().getProject(name);
IProjectDescription description =
bareProjectHandle.getWorkspace().newProjectDescription("TestProject");
description.setLocationURI(bareProjectHandle.getLocationURI() );
IProject bareProject =
CCorePlugin.getDefault().createCDTProject(description, bareProjectHandle, new NullProgressMonitor() );
IManagedBuildInfo buildInfo = ManagedBuildManager.createBuildInfo(bareProject);
IManagedProject projectManaged =
ManagedBuildManager
.createManagedProject(bareProject,
ManagedBuildManager.getExtensionProjectType("cdt.managedbuild.target.gnu.mingw.exe") );
List<IConfiguration> configs = getValidConfigsForPlatform();
IConfiguration config =
projectManaged.createConfiguration(
configs.get(0),
ManagedBuildManager.calculateChildId(configs.get(0).getId(), null));
ICProjectDescription cDescription =
CoreModel.getDefault().getProjectDescriptionManager().createProjectDescription(bareProject, false);
ICConfigurationDescription cConfigDescription =
cDescription.createConfiguration(ManagedBuildManager.CFG_DATA_PROVIDER_ID, config.getConfigurationData() );
cDescription.setActiveConfiguration(cConfigDescription);
cConfigDescription.setSourceEntries(null);
IFolder srcFolder = bareProject.getFolder("src");
srcFolder.create(true, true, null);
ICSourceEntry srcFolderEntry = new CSourceEntry(srcFolder, null, ICSettingEntry.RESOLVED);
cConfigDescription.setSourceEntries(new ICSourceEntry[] { srcFolderEntry });
buildInfo.setManagedProject(projectManaged);
cDescription.setCdtProjectCreated();
IIndexManager indexMgr = CCorePlugin.getIndexManager();
ICProject cProject = CoreModel.getDefault().getCModel().getCProject(bareProject.getName() );
indexMgr.setIndexerId(cProject, IPDOMManager.ID_FAST_INDEXER);
CoreModel.getDefault().setProjectDescription(bareProject, cDescription);
ManagedBuildManager.setDefaultConfiguration(bareProject, config );
ManagedBuildManager.setSelectedConfiguration(bareProject, config );
ManagedBuildManager.setNewProjectVersion(bareProject);
ManagedBuildManager.saveBuildInfo(bareProject, true);
return bareProject;
}
As I discovered when debugging, it is indeed important to set proper configurations and descriptions as the indexer was postponed so long as the project didn't have those features set. To get the configurations for the platform as a starting point for an initial configuration:
public static List<IConfiguration> getValidConfigsForPlatform() {
List<IConfiguration> configurations =
new ArrayList<IConfiguration>();
for (IConfiguration cfg : ManagedBuildManager.getExtensionConfigurations() ) {
IToolChain currentToolChain =
cfg.getToolChain();
if ( (currentToolChain != null ) &&
(ManagedBuildManager.isPlatformOk(currentToolChain) ) &&
(currentToolChain.isSupported() ) ) {
configurations.add(cfg);
}
}
return configurations;
}
This basically answers the second part of the question, and thus I can create a c project for the purposes of testing code using the index. The testing code still needs to do some work.
Testing Code
I create files in the the "src" folder in the project (created in the above code), and I either have to name them .c, or if I want to name them .h have them included by some .c file (otherwise the indexer won't see them). Finally, I can populate the files with some test code. To answer number 1,
I need to block on both auto refresh jobs in Eclipse and then the index:
public static void forceIndexUpdate(IProject project) throws Exception {
ICProject cProject = CoreModel.getDefault().create(project);
Job.getJobManager().join(ResourcesPlugin.FAMILY_AUTO_REFRESH, null);
CCorePlugin.getIndexManager().reindex(cProject);
CCorePlugin.getIndexManager().joinIndexer(IIndexManager.FOREVER, new NullProgressMonitor() );
assertTrue(CCorePlugin.getIndexManager().isIndexerIdle() );
assertFalse(CCorePlugin.getIndexManager().isIndexerSetupPostponed(cProject));
}
After I change the files in the project. This makes sure Eclipse is refreshed, and then makes sure the indexer completes without being postponed. Finally, I can run tests depending on the indexer.
And the last point, I was wrong about using IBinding. The correct way in which I was able to get the macros was using the method IIndex.findMacros(char[] name, IndexFilter filter, IProgressMonitor monitor)
I hope this helps at least someone out there. I would also appreciate it if there was some feedback regarding the validity of this solution, as this is simply the first solution I managed to create that worked. Just to confirm, I am not testing the indexer itself, but rather code I wrote that uses the indexer and I want to test it under as realistic conditions as I can given how critical it is.

Changing a value for debug and production in java/android

I have a java statement like this:
int MAX_CACHE_AGE = TimeUnit.DAYS.toMillis(14);
And I want to have a max cache age of 0 when debugging. However, I also want to minimize the complexity of my build. What are some ways I can do this? How do you do this? I am developing for Android so if your method is Android specific, tell my anyway.
Initialize this variable in the onCreate() method if it's in an application component, or in the constructor if it's in a normal Java class. The Android tools have a BuildConfig class that is auto generated. You can use its DEBUG field to alter the value.
if(BuildConfig.DEBUG) {
MAX_CACHE_AGE = TimeUnit.DAYS.toMillis(0);
} else {
MAX_CACHE_AGE = TimeUnit.DAYS.toMillis(14);
}

How to add parameters to test cases in Test Plan using Java?

I've tried various things and googled multiple hours but couldn't find a solution to my problem.
I'm using the Quality Center OTA API via Com4j to let my programm communicate with QC.
It works pretty good, but now I've stumbed upon this problem:
I want to add new parameters to a test case in "Test Plan" using my programm.
If I used VB it would work somehow like this:
Dim supportParamTest As ISupportTestParameters
Set supportParamTest = TDConnection.TestFactory.Item(5)
Set testParamsFactory = supportParamTest.TestParameterFactory
Set parameter = testParamsFactory.AddItem(Null)
parameter.Name = name
parameter.Description = desc
parameter.Post
Set AddTestParameter = parameter
The important part is the call of AddItem() on the TestParameterFactory. It adds and returns a parameter that you then can give a name and description. In VB the AddItem-method is given Null as argument.
Using Java looks similar at first:
First I establish the connection and get the TestFactory (and the list of test cases).
QcConnect qc = new QcConnect(server, login, password, domain, project);
ITDConnection qcConnection = qc.getConnection();
ITestFactory qcTestFactory = qcConnection.testFactory().queryInterface(ITestFactory.class);
IList qcTestList = qcTestFactory.newList("");
qcTestList contains all tests from Test Plan.
ITest test = qcTestList.item(1);
ISupportTestParameters testParam = test.queryInterface(ISupportTestParameters.class);
ITestParameterFactory paramFac = testParam.testParameterFactory().queryInterface(ITestParameterFactory.class);
No problem so far. All the "casts" are successful.
Now I want to call the addItem-method on the TestParameterFactory, just like in VB.
Com4jObject com = paramFac.addItem(null);
This doesn't work. The addItem()-method always returns null. I've tried various arguments like a random String, a random Integer, the test case's ID, etc. Nothing works.
How do I use this method correctly in Java?
Or in general: How do I add parameters to existing test cases in Test Plan using Java?
Quick note: Adding test cases to Test Plan works very similar to adding parameters to this test cases. You also use a factory and a addItem-method. In VB you give null as parameter, but in Java you use a String (that's interpreted as the name of the test). But as I said, that does not work in here.
I have finally found the answer to this:
Com4jObject obj = iTestParameterFactory.addItem(new Variant(Variant.Type.VT_NULL));
iTestParameter = obj.queryInterface(ITestParameter.class);
iTestParameter.name("AAB");
iTestParameter.defaultValue("BBB");
iTestParameter.description("CCC");
iTestParameter.post();
Regards.
What you want to pass to AddItem is DBNull and not null.
In VB it's the same, but in Java & .NET it's not.
Not sure how DBNull is exposed using Com4J.
Read more about this at this site.
//C# code snippet -> You have to use DBNull.Value instead of null
//Add new parameter and assign values
TestParameter newParam =(TestParameter)tParamFactory.AddItem(DBNull.Value);
newParam.Name = "ParamNew";
newParam.DefaultValue = "DefaultValue";
newParam.Description = "AnyDesc";
newParam.Post();

How do I create a List of generic arrays in Java?

I've written a class which accepts a generic type, and I'm trying to create an array list of generic arrays within it. I understand that Java can't create generic arrays, but I also know there are workarounds. Is there a way the below code can work, or am I barking up the wrong tree?
public class IterableContainer<T extends IterableItem> {
private T[] itemArray;
// how can i get this following line to work?
private List<T[]> items = new ArrayList<T[10]>();
public IterableContainer() {
... etc ...
Ignore past here - turns out it was an IDE issue.
Left in for continuity of questions and answers.
EDIT:
This also doesn't work:
private List<T[]> items = new ArrayList<T[]>();
with the error:
Syntax error on token ">", VariableDeclaratorId expected after this token
"... barking up the wrong tree..., use a List<List<T>>. Using raw arrays in Java is almost always a code smell, there is no reason not to use the proper collection classes.
It works just fine, you just can't use the T[10] declaration as the length of an array doesn't affect its type.
i.e.
... = new ArrayList<T[]>();
Not saying it's a great idea, but it should be possible with the same restrictions on generic arrays as always. Creating stuff to put in your list will give you a headache.
private List<T[]> items = new ArrayList<T[]>();
works fine in my machine
When you say "I'm developing for mobile devices" ....are you targeting j2me? There is no support for generics in j2metargetng
This is a valid declaration in java (according to spec) and compiles just fine with javac as others have commented.
public class IterableContainer<T extends IterableItem> {
private T[] itemArray;
private List<T[]> items = new ArrayList<T[]>();// valid
..........
}
I believe the error you are seeing is not emitted from Eclipse, possibly coming from an Android SDK configured in Eclipse. If you create a Java Project in Eclipse, this code should work just fine. If you use this in an Android Project in Eclipse, you are likely to run into this one. I had this error when running this code from an Android project :
# guarantee(_name_index != 0 && _signature_index != 0) failed: bad constant pool index for fieldDescriptor
Sounds like you are restricted in an Android project, unfortunately.
You have not defined T in this code.
If you are creating a generic class, you need to write:
public class <T extends IterableItem> IterableContainer...
The next problem in your code is that you are trying to initilize items of ArrayList during its construction. It is impossible. You should rather write:
private List<T[]> items = new ArrayList<T[]>();

Categories

Resources