diff --git a/README.md b/README.md index 82803d1..132a067 100644 --- a/README.md +++ b/README.md @@ -113,3 +113,10 @@ Even if you are not using code obfuscation, you can still use this gem to map Java class names to their original file paths, as Java stack traces do not include the full path to source files, which Squash needs to perform its Git-blame magic. + +ADDED ANNOTATIONS +------------------- +This branch contains the code of the SquashBacktrace.java that are now with Nullness Annoatations which ensures that the program will never throw a null pointer exception. +Files Updated are : +1.SquashBacktrace.java +2.pom.xml diff --git a/commands.txt b/commands.txt new file mode 100644 index 0000000..7c0faea --- /dev/null +++ b/commands.txt @@ -0,0 +1,4 @@ +/*commands for SquashBacktrace.java*/ +(compiling): +"java -jar "C:\Program Files\checker-framework-2.3.2\checker-framework-2.3.2\checker\dist\checker.jar" -processor nullness SquashBacktrace.java" +Hope there's is no compilation error diff --git a/pom.xml b/pom.xml index 9ce4fe3..67bb068 100644 --- a/pom.xml +++ b/pom.xml @@ -79,6 +79,11 @@ ${gson.version} test + + org.checkerframework + checker + 2.2.1 + diff --git a/src/main/java/com/squareup/squash/SquashBacktrace.java b/src/main/java/com/squareup/squash/SquashBacktrace.java index a5edc53..99f5619 100644 --- a/src/main/java/com/squareup/squash/SquashBacktrace.java +++ b/src/main/java/com/squareup/squash/SquashBacktrace.java @@ -14,6 +14,9 @@ package com.squareup.squash; +import org.checkerframework.checker.nullness.qual.*; +import static org.checkerframework.checker.nullness.NullnessUtil.castNonNull; +import org.checkerframework.framework.qual.*; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.util.ArrayList; @@ -21,14 +24,15 @@ import java.util.List; import java.util.Map; +@AnnotatedFor({"nullness"}) /** Creates the Squash stacktrace format for serialization by gson. */ public final class SquashBacktrace { private SquashBacktrace() { // Should not be instantiated: this is a utility class. } - - public static List getBacktraces(Throwable error) { + //adding the annotation @Nullable as the return type may include a null value + public static @Nullable List getBacktraces(Throwable error) { if (error == null) { return null; } @@ -42,15 +46,20 @@ public static List getBacktraces(Throwable error) { private static List getStacktraceArray(Throwable error) { List stackElems = new ArrayList(); for (StackTraceElement element : error.getStackTrace()) { - StackElement elementList = - new StackElement(element.getClassName(), element.getFileName(), element.getLineNumber(), - element.getMethodName()); + @SuppressWarnings("nullness") StackElement elementList = + new StackElement(element.getClassName(),element.getFileName(), element.getLineNumber(), + element.getMethodName());/*The constructor of the StackElement class requires non-null + type arguments,but the method call element.getFileName() might + return an null value,it can be resolved by modifying parameter of the + constructor by adding the annotattion @Nullable, but for now the annotation @SuppressWarnings("nullness") + can be added assuming it doesn't return a null value and suppressing it + if it does,without crashing the program. */ stackElems.add(elementList); } return stackElems; } - - public static Map getIvars(Throwable error) { + //adding the annotation @Nullable as the return type may include a null value + public static @Nullable Map getIvars(Throwable error) { if (error == null) { return null; } @@ -63,7 +72,12 @@ public static Map getIvars(Throwable error) { if (!field.isAccessible()) { field.setAccessible(true); } - Object val = field.get(error); + Object val = castNonNull(field.get(error));/*Ivars is a HashMap object, we can't allow a nullable + value at the place of a value for a specific key in the + put() method of the HashMap.The castNonNull() method of + NullnessUtil class can be used as this method takes a + possibly null reference unsafely casts it to have the @NonNull + type qualifier.As it's an expression statement @SuppressWarnings("nullness") can't be used.*/ ivars.put(field.getName(), val); } } catch (IllegalAccessException e) { @@ -84,9 +98,15 @@ public static void populateNestedExceptions(List nestedExceptio return; } final Throwable cause = error.getCause(); - NestedException doc = + @SuppressWarnings("nullness") NestedException doc = new NestedException(cause.getClass().getName(), cause.getMessage(), getBacktraces(cause), - getIvars(cause)); + getIvars(cause));/*The contructor of the NestedException class can't take a null value,but the three method calls + 1. cause.getMessage() , 2. getBacktrace(cause), 3.getIvars(cause) may return null values, + resolved it using @SuppressWarnings("nullness") reasons: + 1. cause.getMessage() : the constructor itself can be modified with the annotation @Nullable + 2.getBacktrace(cause) : have a return type annotated with @Nullable(see line no. 33) + 3.getIvars(cause) : have a return type annotated with @Nullable(see line no. 61), + the method castNonNull() of the NullnessUtil class can't be used as there are chances of getting a null value.*/ nestedExceptions.add(doc); // Exceptions all the way down! populateNestedExceptions(nestedExceptions, cause);