Showing posts with label planeteclipse. Show all posts
Showing posts with label planeteclipse. Show all posts

Sunday, July 8, 2012

Using null annotations for fields (currently beta) in Eclipse JDT Juno

It is common knowledge by now that Eclipse Juno's JDT shipped with support for null annotations for inter-procedural null analysis. This was very well-received and the work made it to several blogs about the 10 most interesting Eclipse Juno features. While this is only applicable to local variables/method parameters for now, I had also blogged about null analysis support for fields while we worked on it. However, due to the sheer complexity of dealing with problems such as aliasing, concurrency, etc with fields and the current infrastructure's limitations in dealing with these issues comprehensively, we had to withdraw this feature. Because of this, Juno did not come with null annotations support for fields.

However, the good news is that along with the Juno release, the JDT team, with all due credits to Stephan Herrmann, also released a public beta version of null annotations support for fields. Please visit the null analysis beta wiki page to learn about installation and usage of this feature. As Stephan puts it in his post on DZone, "feedback to this experimental solution should help us to decide what will be JDT's final solution regarding null analysis for fields". So, please start using it if you've upgraded to Eclipse Juno. If not, what are you waiting for? ;)

Friday, March 2, 2012

Contributing to Eclipse Java Development Tools project

In recent times, we've been getting several contributions in the Eclipse JDT project. Thats a great thing and we want to encourage that. However, several times small issues viz. patch not based on latest code, formatting issues, whitespace issues, failing tests etc. delay the process of review and release. It is painful for both the contributor, as well as the JDT committer.

In order to make sure all JDT contributions go through a standard series of steps before they make it to bugzilla, we've updated the contributing to JDT/UI and the JDT/Core FAQ page. Please spend a few minutes reading through the steps and go ahead to submit a patch on bugzilla. Looking forward to more community participation in both JDT projects.

Also, whenever you start working on a bug, please drop a small comment on the bug page to say you intend to submit a patch, to avoid duplication of effort. Thanks! :)

Saturday, February 18, 2012

Null analysis for fields in Eclipse JDT withdrawn for Juno

Null analysis for fields with Eclipse JDT , introduced in Juno M5, has been withdrawn and will not be available in the Juno release. Only Juno M5 will contain this feature. The reason for withdrawal is the fact that becuase of implementation constraints, it could not support analysis for alien field references i.e. non-static fields of objects other than 'this'. We will rework the implementation and come back with a full fledged support for fields, including annotations to support null analysis for fields. See https://bugs.eclipse.org/bugs/show_bug.cgi?id=247564#c176 for more details.



Apologies to those who were looking forward to a complete null annotations support for fields as well. We are considering making the current implementation of the feature available as a plugin patch. I will keep you posted.

Also, even when using annotations for method return and parameters, be careful in dealing with fields because we don't warn there. Eg:

class A{
     Object o = null;

     void goo(@NonNull Object param) {}
     @NonNull Object foo() {
            goo(this.o);
            return this.o;
       }
}

Monday, January 30, 2012

Null Analysis for Fields with Eclipse JDT

It is common knowledge that Eclipse has an intra-procedural null analysis capability, augmented recently with null annotations for inter-procedural analysis in Juno M4. However, a big flaw and pain point till now was that the anlsysis would only work for local variables/parameters, and NOT for fields! Strange, innit? Well, a bunch of problems with handling fields prevented the initial null analysis implementation to be generic enough to handle fields as well. Access from different threads, through different objects, initialization of even final fields in different constructors were some of the roadblocks because of which this work was put on the backburner. However, even though we haven't found a holy grail to tackle these problems, we've come out with atleast a basic implementation of null analysis for fields! Rejoice!

A. The Problem
Prior to Juno M5, the following code snippet would raise null warnings only on the local variable, but not on the field.


B. The Solution
See the Juno M5 new and noteworthy page for the new null analysis for fields.
Note that for non-constant fields, we only raise "potential NPE" warnings even if the field has been assigned null or compared against null because we assume that there's always a chance of another thread modifying it between the assignment/comaparison and the actual reference. So consider the following snippet


C. Not quite there yet?
There are a few limitations with the current null analysis for fields:
  • Yet to be done for final fields that are initialized at the time of declaration. This will be done with the fix for bug 237236 soon.
  • The analysis only works for non-static fields of the current object or static fields of the current type ONLY. That means, in the following code snippet. you get null warnings on direct access of field1 or access via "this", but not if field1 is accessed via another object 'test'.
class Test{
   public Object field1;

   void foo(Test test) {
      if (field1 == null) { 
         System.out.println( field1 .toString());  // "potential" NPE warning
     } else {
        // do something
     }
     System.out.println(field1.toString());  // Potential NPE warning here

     if (this.field1 == null) { 
         System.out.println( this.field1 .toString());  // "potential" NPE warning
     } else {
        // do something
     }
     System.out.println(this.field1.toString());  // Potential NPE warning here
    // access through object 'test' will raise no warnings. See below

     if (test.field1 == null) { 
         System.out.println( test.field1 .toString());  // no warning
     } else {
        // do something
     }
     System.out.println(test.field1.toString());  // no warning


  }
}

This is a limitation of the current code analysis infrastructure and we hope to address this sometime soon. The soon to be released null annotations support for fields will greatly assuage this problem in the short term.

Please do start using this new feature. Even with its limitations, its quite useful and we've found a long list of unsafe code patterns in the Eclipse SDK itself. Deepak's post here presents one such example


Apart from this, Juno M5 has more interesting items. See my previous post on pre-built indexes, Stephan's post on Resource leak warnings and the Juno M5 new and noteworthy page for more.

Stay tuned!



Thursday, January 26, 2012

Faster Java search using pre-built indexes with Eclipse JDT

JDT indexes referenced libraries (or JARs) in your projects for use in the Java search. However, in most cases these libraries seldom change, and the indexing may be costly and take time when you invoke search for the first time after adding the JAR on the buildpath.

From 3.8M5 onwards, you can avoid this redundant indexing by providing a pre-built index for each classpath entry in the classpath container. This feature was recently implemented in bug 356620.

So how do you generate the indexes in the first place?
1. Create the JAR
2. Go to Run Configurations>Eclipse Application. Give a name to the configuration, viz. indexer, and in 'Main' tab choose Run an application, and use the list to select org.eclipse.jdt.core.JavaIndexer

3. Go to the 'Arguments' tab and use the arguments -option <indexFileLocation> <jarFileLocation> in addition to the existing ones.

4. The index file will be generated at the specified location.

Now when the JAR in question is being added to the build path of a project, the classpath containers can add the index location to classpath, which will look as follows:

<classpathentry kind="lib" path="C:/Users/IBM_ADMIN/Desktop/TestIndex.jar">
<attributes>
<attribute name="javadoc_location" value="file://C://abc"/>
</attributes>
</classpathentry>

Voila! JDT will no longer index the JAR and even the first search will be lightning fast!

Note: This feature is mainly intended for plug-ins that implement their own classpath container, not for the end user.

Tuesday, December 6, 2011

Inter-procedural Null analysis using annotations in Eclipse JDT

The JDT team is extremely excited with the release of the new annotation based null analysis. Before writing anything about it I want to thank Stephan Herrmann (JDT committer from Germany) for all the hard work he has put in on this feature! Feel free to drop him a word of appreciation on stephan AT cs.tu-berlin.de

What is JDT's annotation based null analysis?
To give a bit of a background, you must've noticed that JDT java compiler does some static analysis and based on that warns if you deference a variable that has been analysed to be (potentially) null at runtime, or compare a variable against null when its nullness at runtime can be determined at compile time.

[See line numbers to locate error messages]
However, the warnings are only generated for local variables inside a method. There's no way to find out the change of nullness due to a method call, or for parameters of a method. Consider the example on the left. o1 is a parameter and since we don't know how foo(..) will be called and what value will be passed to o1, we can't do any analysis on it unless its state definitely changes inside foo(..). Also note that even though o1 is assigned return value of method  bar(), which returns null, the compiler cannot figure that out during static analysis and assumes the return value of bar() to be an unknown value.

Null annotations offer a solution here. They are a way of enforcing null contracts in your code to make sure you catch such (potential) NPE's before they occur at runtime and become a stop-ship bug for your product.


How do I use null annotations?
JDT now comes bundled with a JAR (org.eclipse.jdt.annotation) containing null annotations. The types of annotations offered are:
NonNull annotation
Default is @org.eclipse.jdt.annotation.NonNull -
  • when this annotation occurs on a return type, it enforces a non null return value for a method.
  • when this annotation occurs on a method parameter, it enforces a non null value to be passed to the method call and that only a non null value can be assigned to this parameter inside the method.

Nullable annotation
Default is @org.eclipse.jdt.annotation.Nullable-
  • when this annotation occurs on a method return type or parameter, it says that the returned value can be null, and so can be the argument.

NonNullByDefault annotation
Default is @org.eclipse.jdt.annotation.NonNullByDefault-

  • This can be applied to a package (in package-info.java), class or method to enforce nullability for all enclosed elements. The annotation alone enforces non nullability of enclosed method return value and parameter values.
  • If applied with a an argument i.e. NonNullBeDefault (false), it will cancel out any global default for the particular element.

To use these annotations in your project, right click Project>Build Path>Add External Archives and browse to org.eclipse.jdt.annotation JAR in the "plugins" directory of your eclipse install location. (We are working on the UI for this.)

One can also use their own annotation types as null annotations. Just make sure they are on the project's buildpath.

To enable null annotation based analysis and specify the annotation names, navigate to Preferences>Java>Compiler>Errors/Warning>Null analysis.

(Note also the "use non-null as default" option, which you can use to set a universal (workspace/project level) default to be applied to all method return types and parameters.)







What new errors/warnings should I expect to see with null annotations enabled?
As seen in the above dialog, there are two kind of diagnostics of primary importance - violation of null specification and potential violation of null specification. In addition to these the existing null analysis gets enhanced, and now for annotated method parameters a null state is available inside a method.

Violation of null spec is issued in cases when:
1. You pass a null value as an argument to a method whose corresponding parameter is annotated with @NonNull
2. You assign a @NonNull annotated parameter a null value.
3. You return a null value in a method that is annotated with @NonNull
4. You inherit a method annotated with @NonNull but now loosen the contract by annotating child method as @Nullable.
5. You inherit a method with a parameter annotated with @Null but now tighten the contract by annotating child method's corresponding parameter as @NonNull.

[See line numbers to locate error messages]



Potential violation of null spec is issued when:
1. You pass a value evaluated to be null on some execution path as an argument to a method whose corresponding parameter is annotated with @NonNull
2. You assign a @NonNull annotated parameter a value ascertained to be null on some execution path.
3. You return a possibly null value in a method that is annotated with @NonNull.

[See line numbers to locate error messages]


Insufficient null info is issued when there's not sufficient information to evaluate a given value to be (possibly) null and that value is passed as an argument, assigned to a parameter or returned from a method.

[See line numbers to locate error messages]


Redundant null annotation is issued when an annotation has the same effect as one applied already in an enclosing element.

[See line numbers to locate error messages]

Note that this is a work in progress and we will continue to polish the same for the Juno release. We're also working on ways to help people use this functionality easily (eg.: Support for nullity profiles for libraries and Quick fixes for null annotations. ) .
For a sneak preview of this feature, drop in at the EclipseCon 2012 tutorial - How To Train the JDT Dragon. If you find any issues while testing this feature, please open a bug. I hope you're as excited as we are about this cool new feature!

Monday, November 14, 2011

Of Compliance and Source settings in Eclipse java compiler


Going through a few stack overflow posts and a few bugs, I realized that there's still a lot of confusion about the  source and compliance level settings available in JDT. Well, frankly, almost everyone I know was confused when they started using JDT, even the current JDT committers themselves!
These settings are available in Preferences>Java>Compiler, or in your project's .settings folder>org.eclipse.jdt.core.prefs file.



So, what do the settings imply and what do they do?

Source compatibility:
This setting should be used to select upto which java version the user intends to use the language features. Eg.: setting it to 1.7 means that the user can use strings in switch, the diamond construct, etc. but setting it to 1.6 will mean that the user can not use such 1.7-only language features.
For the JDT compiler itself, we use a compliance of 1.4. Yes, quite old-fashioned you'd say, but this was a conscious choice to enable people to use the JDT compiler even if they dont have a version of java higher than 1.4 installed on their machines. You can also chose a source setting for your project on such considerations.

Compiler Compliance level:
This setting is a kind of a switch to make the JDT compiler "compliant" to a certain Oracle javac version. This is because not all bugs fixed in the Oracle javac compiler get backported to earlier releases. So, there are many differences between each javac version. There are even cases when only one javac version differs from the others, before and after it. So, we provided the compliance setting for users to replicate that difference in behaviour in the JDT compiler. This is to enable people who compile with ECJ and ship with javac or vice-versa, to see consistent errors (or the lack thereof).

Take, for example, the following case:

package com.example;

import java.util.List;


public class ErasureBug {


    public String output(List<Integer> integers) {


        return "";
    }


    public void output(List<Double> doubles) {


    }
}


This code compiles without error only in javac 6, but fails with a duplicate method erasure in both javac 5 and javac 7. 


So, in Eclipse when the user sets the project "compliance" to 1.6, he/she will be able to compile the code as shown, while in 1.5 and 1.7 modes, the code will fail.




Generated .class files compatibility:
This setting changes the generated bytecode to be compatible to a certain VM version. This is required at runtime when the VM available is lower than the one for which the code is compiled. So, if you set source level at 1.3 , use 1.3 features your code and expect your clients to still be able to use the older 1.2 or lesser VM to execute your code, you should set the .class file compatibility setting to 1.2 or less. This does not work for higher java versions, because suppose you use annotations in your code which only came in 1.5, or instructions such as invokedynamic in 1.7, which introduced a new Bootstrap method attribute, earlier VM's may still not be able to execute the class files. So we cannot guarantee backward compatibility and the UI thus will not allow you to set class file compatibility lower than the source level. However, if you're using features such as generics in 1.5 source level, it's quite safe for a 1.4 VM to execute those. So, you can manually set the org.eclipse.jdt.core.compiler.codegen.targetPlatform property to 1.4 in project>settings folder>org.eclipse.jdt.core.prefs file.


Note that the source level cannot be more than the compliance level.


Hope this gives more clarity on the settings.


EclipseCon update:
I have the following submissions for EclipseCon 2012. Do vote if you find them interesting:



Tuesday, October 18, 2011

Of invalid references to system libraries and execution environments

Picture this:

  • You have a plugin that is supposed to be compatible with systems running even on 1.4 JRE i.e. your plugin execution environment is 1.4.
  • An unsuspecting developer unintentionally checks out this plugin project into his workspace where he uses a 1.6 JRE by default.
  • He starts writing Generics and is even allowed to do so because a 1.6 library is associated with the project in his workspace. The poor guy doesn't yet know what blunder he has done! :)
See an example below where in a plugin with 1.6 compliance, a developer accidentally used Autocloseable (coming from his workspace default 1.7 JRE).

API tooling provides a mechanism to figure out such illegal references to system libraries. In order to set up API tooling for your plugin project, right click on the project > PDE tools > API Tooling setup. Choose your project and click next. When it shows "Add API nature and API analysis builder", click finish. Now make sure your project settings for API tooling (right click > Properties > Plug-in development > API errors/warnings) are set as shown below:

By default, the "Supported Environments" will have no Execution Environments descriptions installed (From 3.8 onwards you will get an error whenever no execution environment description is installed). To install these EE descriptions, click on "install them now" or go to the "Install New Software.." page. Choose the "Eclipse Project update site" if already available or add the URL http://download.eclipse.org/eclipse/updates/<version> , where <version> = 3.6, 3.7, etc.
Uncheck "group by category" option and search for descriptions. Install these descriptions and you're all set to go. (Note: the above steps should be taken if you move to 3.8 Juno and suddenly find the "Missing EE descriptions" error in your project). 

Now with the above "invalid references to system libraries" option set to error/warning, you should get a warning for usage of Autocloseable in the above plugin project, as shown below:


These settings when done once on the project level and released into the repository will make sure that nobody accidentally references any API/class one is not supposed to. Read Olivier's post to know more about project vs. workspace settings

Saturday, July 30, 2011

Java 7: Decoding the new Diamond operator with JDT

Java 7 GA is officially out. Many people have already been trying their hands on the new features, and blogging/commenting about them at various forums. However, I still believe that people do not understand the real meaning of the diamond operator, which brings in "improved type inference for generic instance creation". Being the guy responsible for implementing this feature in Eclipse JDT's BETA java 7 support, I had a tough time understanding the specs at first. But now I have greater clarity. I guess everybody knows by now that diamond operator <> can be used in place of re-specifying type arguments in a class instantiation expression / constructor invocation. This makes the following case quite clear:

Instead of writing the following in java 1.6 and below
List <String> list = new ArrayList<String>();

one can now simply write
List<String> list = new ArrayList<>();

and the compiler will automatically infer that you meant to write ArrayList<String>();

We also know by now, that this is different from
List <String> list = new ArrayList();

since here ArrayList() instantiates a raw type, and the compiler, with -Xlint:unchecked will warn for an unchecked conversion in the above statement.

So far, so good. However, it is worth noting that there's more to it than meets the eye, and people often take a simplistic view of the diamond usage. It is worth remembering that the diamond inference works just like type inference for generic methods, where instead of using <>, it is enough to just forget about specifying anything at all, and leave the inference to the compiler. This is unfortunately or fortunately (depending on whether you prefer to lose your hair or not) a consequence of allowing the diamond operator in ANY class instance creation expression.

Let's take a closer look, and try to understand the various scenarios of diamond usage with the help of Eclipse snippets. The easier part first - let us investigate a couple of cases(i.e. instantiation expressions) where the diamond operator CANNOT be used.
  1. Anonymous class declarations                                        
  2. Explicit type arguments for the constructor: Lets try to understand this further. A constructor can have two sets of type arguments. A constructor in a parameterized type can have type arguments of the class as its type arguments + it may declare its own. In the example shown below, constructor of Diamond uses T, which is the class type argument and also declares another type argument U. In case the constructor also declares its own type arguments, type parameters will be explicitly specified at the constructor invocation. If this happens, and yet the constructor invocation uses the diamond operator to let the compiler infer the first set of types args (i.e. those coming from the class), then it is a compile time error.                                                                             
Now comes the trickier part. Lets see the valid use cases of the diamond operator. Consider the following (simplest) case and let us see how the inference of type arguments work.


This case is straightforward. The constructors are pretty much chosen by the standard overloading mechanism.  However, this might create the simplistic view that the compiler simply substitutes the type from the RHS in place of the <> operator i.e. in the above case, <> is substituted as String and hence T = String. So all constructors are valid. Let us try understand how this works with a tweaked example:




Oops! This gives a compile error, even though going by the above simplistic view, at line 15, <> should be inferred as Number and hence, T= Number, which means this should be valid. However, even though simple, this is not the way the compiler infers type for the diamond. On the contrary, it tries to :
  1. find the matching constructor call with 1 argument, which in the above case, means DiamondTest(T t)
  2. It then substitutes the formal parameters of this constructor with the parameters that have been passed at the call site. So, T becomes Integer. (In case of default constructor, or where no type argument is substituted in the matching constructor, by default T gets inferred as Object).
  3. Using the inferred type arguments from 1 and 2, the compiler determines the type of the instantiation expression and the exceptions thrown. Hence in this case, new DiamondTest<>(1) gets translated as new DiamondTest<Integer>(1).
Hence, the compile error.  Now let us see some more use cases of the diamond operator:
  • Inner classes

Note how the statement at line 21 is not allowed since the new DiamondTest<>() is inferred as new DiamondTest<Object>(). Also, note that as of today, even statement 20 does not work with Oracle Javac because of a bug in their compiler. However, Eclipse JDT compiler correctly compiles it! :)

  • Non-variable declaration statements
 

  • Return statements
 
  • Conditional operators


However, note how the following results in an error
 

We can construct many more scenarios, but in the interest of time (yours and mine ;) ), I'll  leave it here. Go ahead, experiment with the diamond with Eclipse. The Eclipse work for JAVA 7 that was being done in the BETA_JAVA 7 branch has now been merged into the HEAD and R_3_7_maintenance streams and so, you can try next week's builds in either 3.8, 3.7.x or 4.2 streams to get your hands dirty on Java7. Some new JDT features with respect to the diamond operator are:
  • Content assist is diamond aware. Wherever legal and non-ambiguous, content assist will insert <> and not the type arguments. Ex: List<String> l = new Arra|  is completed to List<String> l = new ArrayList<>();
  • Configurable compiler warning on redundantly specified type arguments.
  • Quick assist (CTRL+1) to insert type arguments 
     
For a preview of more new Java 7 features in Eclipse JDT, check out Deepak's blog. If you find any bugs, please open a bug with [1.7] in the summary. Most of the Eclipse JDT team will be at IBM Rational Innovate India 2011, Bangalore on August 10 and 11, 2011. Catch us there!