Showing posts with label NetBeans. Show all posts
Showing posts with label NetBeans. Show all posts

Saturday, May 30, 2020

Octopus Scanner: Java Build Tools and Malware

Alvaro Muñoz recently posted "The Octopus Scanner Malware: Attacking the open source supply chain" on the GitHub Security Lab site. I found this post to be interesting for a number of reasons, including its detailed coverage of how the Octopus Scanner malware works and how it was discovered, how the GitHub Security Incident Report Team (SIRT) went about addressing it, how it affected a popular Java IDE, and how GitHub works to detect and address risks to open source software deployed on its site.

Muñoz calls Octopus Scanner "an OSS supply chain malware" and writes that 26 GitHub-hosted open source projects "were backdoored by this malware." In the post, Muñoz describes in detail how Octopus Scanner works. The post in its entirety is worth reading, but here are some highlights describing Octopus Scanner:

  • "Octopus Scanner malware is only interested in the pre-jar and post-jar tasks" of "a NetBeans project build."
  • "The malware disguises itself as an ocs.txt file, but we can easily determine is is actually a Java Archive (JAR) file."
  • "The malware also infected any JAR files that were available in the project, such as dependencies - not necessarily just build artifacts."
  • "The octopus.dat payload is the binary that actually performs the NetBeans build infections."
  • "cache.dat is responsible for backdooring the built classes so that when these classes get executed, they will infect the underlying system."
  • Octopus Scanner is designed to target "UNIX-like systems", MacOS, and Windows.

I found the highly detailed approach to diagnosing Octopus Scanner's behavior in the GitHub post to be fascinating and insightful reading. It was especially insightful to see the tools and methods used to understand better how Octopus Scanner behaves. For example, they used ClassFileTransformer and "a Bytecode manipulation library such as Javassist or ByteBuddy to inject our analysis code" into the "class responsible for decrypting the blob ... right before it actually gets loaded into the JVM."

Besides the interesting details of how Octopus Scanner works and how it was discovered and researched, other interesting insights in this GitHub post are related to the risks open source builds face. Muñoz writes, "Infecting build artifacts is a means to infect more hosts since the infected project will most likely get built by other systems and the build artifacts will probably be loaded and executed on other systems as well." Muñoz adds, "In an OSS context, it gives the malware an effective means of transmission since the affected projects will presumably get cloned, forked, and used on potentially many different systems. The actual artifacts of these builds may spread even further in a way that is disconnected from the original build process and harder to track down after the fact."

Muñoz opens the post and concludes the post with some discussions about this and other attempts at sabotaging open source products and their builds. One chilling thought is included in the Conclusion: "Since the primary-infected users are developers, the access that is gained is of high interest to attackers since developers generally have access to additional projects, production environments, database passwords, and other critical assets. There is a huge potential for escalation of access, which is a core attacker objective in most cases."

Tuesday, September 13, 2016

Apache NetBeans?

It's fairly common to have significant announcements related to the world of Java released in the days and weeks leading up to JavaOne. With that in mind, it's not surprising that we're seeing some significant Java-related announcements just prior to JavaOne 2016 that begins next week. One announcement is Mark Reinhold's Proposed schedule change for JDK 9 in which Reinhold proposes "a four-month extension of the JDK 9 schedule, moving the General Availability (GA) milestone to July 2017." Another major proposal, the subject of this post, is the proposal by Oracle for Oracle to "contribut[e] the NetBeans IDE as a new open-source project within the Apache Incubator."

The Apache NetBeans proposal is summarized on NetBeans.org, but additional details are available on Apache Software Foundation's Incubator Wiki page called NetBeansProposal. The NetBeansProposal Wiki page provides several details related to the benefits, costs, and risks associated with moving NetBeans to the Apache Software Foundation. Additional views on this proposal that summarize or interpret the proposal can be found in online resources such as Proposal has NetBeans moving to Apache Incubator, Oracle's NetBeans Headed to The Apache Software Foundation, Oracle no more - NetBeans is moving to Apache, Java founder James Gosling endorses Apache takeover of NetBeans Java IDE, An unexpected proposal: Oracle bids farewell to NetBeans, and Oracle Proposes NetBeans IDE as Apache Incubator Project. There are also two Reddit threads on this subject on the subreddits programming and java.

I've felt for some time that the open source projects I'm most willing to "take a chance on" and recommend to management and customers are those that have either strong corporate sponsorship or are affiliated with an established and successful umbrella organization such as Apache Software Foundation. Therefore, although I don't like to see NetBeans lose the corporate backing and investment of Oracle, the Apache Software Foundation does provide a home for NetBeans to continue being a successful project.

Like many software developers who have been working in this area for years, I've been using Apache Software Foundation projects for most of those years. The liberal Apache 2 license is welcoming and uncomplicated. The projects tend to be well run and well used. On occasion when projects are no longer active, the ASF is fairly timely in moving such projects to the Apache Attic. Projects associated with ASF tend to enjoy benefits often associated with open source such as multiple contributors including multiple reviewers and real-life "testers." Many of the ASF projects enjoy a large community with the accompanying benefits of a large community such as improved main site documentation as well as third-party supplemental documentation with blogs, books, and articles. Of course, NetBeans already enjoys much of this, so moving to ASF might be more of an approach to retain some of the advantages it already enjoys while at the same time potentially encouraging greater community collaboration.

The Apache Software Foundation projects I've used over the years seem to come from two different types of origins. Some of them have been associated with ASF from their beginning or almost their beginning while others were popular projects already when they were moved to the ASF. NetBeans falls in the latter category with other projects that I used before they went to ASF such as Groovy (from SpringSource/Pivotal) and Flex (from Adobe). It seems likely that Oracle has proposed donating NetBeans to Apache Software Foundation for the same reasons that Pivotal and Adobe donated Groovy and Flex respectively to Apache Software Foundation.

The examples just mentioned (Adobe|Flex, Pivotal|Groovy, and Oracle|NetBeans) are just a subset of examples that could be cited in which corporations who are the sponsors and dominant contributors have given away the open source project, typically with the intent to spend fewer resources managing that project. If NetBeans is able to enjoy significant community contributions, the disadvantages of reduced corporate sponsorship might be at least partially offset. Some of this, of course, depends on what level of involvement Oracle supports its employees in contributing to NetBeans.

When Oracle acquired Sun, many of us wondered about the future of GlassFish (Oracle had already acquired WebLogic from BEA) and NetBeans (Oracle already had a free, but not open source, Java IDE in JDeveloper). Oracle announced in 2013 that GlassFish 4.x would not be available as a commercial offering and would only continue as an unsupported Java EE reference implementation (though third-party support can be found for the "drop-in replacement" Payara Server). Although there are some advantages to this "developer-friendly" reference implementation in terms of trying new Java EE features and learning Java EE concepts, most Java EE developers I'm aware of who use an open source Java EE application server for production have moved to WildFly. Given this, I've been happy to see NetBeans moving along and being supported as well as it has for as many years as it has.

One potentially new prospect for NetBeans is being the basis for more specialized IDEs. Eclipse has long been the basis of specialized IDEs and development tool suites such as Spring Tool Suite (Spring IDE), Oracle Enterprise Pack for Eclipse, Adobe Flash Builder, Red Hat JBoss Developer Studio, and Zend Studio. Similarly, Android Studio is built on IntelliJ IDEA. Although there are already tools based on NetBeans (such as VisualVM), NetBeans's independence from Oracle may seem more attractive to some for future tools' development.

At the time of this writing, the NetBeansProposal Wiki page already lists 63 people in "the initial list of individual contributors" (including 26 people contributors associated with Oracle). That, along with the extensive resources already available related to NetBeans, encourage me and make me think that NetBeans could be a successful and thriving Apache Software Foundation project. I certainly prefer NetBeans's chances as an Apache Software Foundation project over its chances if it existed in a state similar to that placed upon GlassFish.

We Java developers are fortunate to have multiple very strong IDEs available for our use. It's in our best interest if they can each remain strong and viable as all the IDEs (and the developers who use them) benefit from the competition and from the innovation that talented developers working on these IDEs bring to our development experience. Each of the IDEs offers different advantages and has different strengths and I'm hoping that we can benefit from NetBeans's current strengths and future strengths for years to come.

Monday, November 2, 2015

Applying IDE Inspections to Custom Java Annotations

The introduction of annotations with J2SE 5 has changed how we write and process Java. Besides Java SE's predefined annotations, frameworks, IDEs, and toolkits have introduced their own custom annotations. The Checker Framework has provided examples of how custom annotations can be used to add greater type safety in Java. In this post, I look at the writing of a simple custom annotation and using it in NetBeans (8.0.2) and IntelliJ IDEA (14.0.3) to help developers identify issues in their code that need further attention.

In the article Making the Most of Java's Metadata, Part 2: Custom Annotations, Jason Hunter demonstrates an @Unfinished annotation as an example of writing a custom Java annotation. I will demonstrate a different implementation of an @Unfinished annotation in this post. That's the beauty of custom annotations: one can write an annotation to best fit one's needs. The code for my @Unfinished annotation is shown in the next code listing.

Unfinished.java: Defining Custom @Unfinished Annotation

package dustin.examples.annotations;

import static java.lang.annotation.ElementType.*;

import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * Example of a custom annotation that marks Java code constructs
 * that are not yet completed.
 *
 * Notes about custom annotations specific to this example:
 *   - @Documented indicates available for public documentation
 *   - CLASS retention policy means that compiler places annotation
 *     information in compiled .class files, but JVM is NOT aware
 *     of the annotation at runtime.
 *   - @Target parameters (statically imported) indicate that this
 *     annotation can be applied to constructors, fields,
 *     local variables, methods, packages, parameters, and
 *     classes/interfaces.
 *   - Methods defined for this @interface without 'default' are
 *     required settings for application of this annotation. In
 *     this case, the "finishBy" element is NOT required (but
 *     recommended!) but the "value" element is required.
 *   - "value" element has special significance in custom Java
 *     annotations: it is the assumed annotation element if
 *     a String is provided to the annotation without explicit
 *     element name called out.
 */
@Documented
@Retention(RetentionPolicy.CLASS)
@Target({CONSTRUCTOR,FIELD,LOCAL_VARIABLE,METHOD,PACKAGE,PARAMETER,TYPE})
public @interface Unfinished
{
   /** Description of the unfinished construct. */
   String value();

   /**
    * Date, build, or event by which the annotated construct
    * is anticipated to be finished.
    */
   String finishBy() default "Unknown";
}

The next code listing shows application of @Unfinished in a simple class that has a lot of work still to be completed on it.

WorkInProgress.java: Applying @Unfinished Custom Annotation

package dustin.examples.annotations.demo;

import dustin.examples.annotations.Unfinished;

/**
 * Demonstrates custom Java annotation @Unfinished.
 */
public class WorkInProgress
{
   @Unfinished("This will do something good by Revision 2.")
   public void doSomethingGood()
   {
   }

   @Unfinished(value = "Do something good here.", finishBy = "Revision 2")
   public void doSomethingElseGood()
   {
   }
}

The incomplete class uses the annotation's "value" element by default for one method and then adds use of the "finishedBy" element for the second method. There are a few observations that can be made from the last two code listings definition or and use of @Unfinished:

  1. Inclusion of "default" for an annotation element means that those who use the annotation are not required to provide a value for that element.
  2. The "value" element is assumed if only one value is provided to the annotation and is provided without an explicit element name.
  3. The name "value" does not need to be provided if only a single annotation element is specified, but must be provided if more than one annotation element is specified.
  4. The retention level of CLASS was used here because I felt like tools working with the compiled version of Java classes would be able to use this information and I don't anticipate runtime use of the information.
  5. Careful selection of which annotation elements should have "default" values is desirable because not having a "default" requires an element to be specified, which can be the desired behavior in some cases.

Use of custom annotations can provide a standardized mechanism for building "executable" and more controlled descriptions for other developers and for tools. This approach is often advantageous when compared to leaving messages with comments as comments tend to be less standardized and subject to typos and differences in case sensitivity, spelling, and other discrepancies. Annotations enforce conventions better and allow for tooling to make more efficient use of what they communicate than parsing arbitrary text. Perhaps the most obvious way to gain some of this benefit of custom annotations over arbitrary comments is with an annotation processor. Several IDEs and frameworks such as the Checker Framework process annotations. There are also numerous online references regarding writing of custom annotations processors that can be used with the Jav compiler to provide warnings. In the remainder of this post, I focus on how one can apply two of the more popular Java IDEs (NetBeans and IntelliJ IDEA) to report these annotations as hints/inspections. I am not looking in this post at integrating an annotation processor into the IDEs' compilation processes or at integrating a custom processor with the command-line Java compiler.

Inspecting the @Unfinished Annotation in NetBeans

I have blogged before on Creating a NetBeans 7.1 Custom Hint and the process is pretty much the same still with NetBeans 8. The first step is to use the Refactor -> Inspect and Transform ... option as shown in the next screen snapshot.

When Refactor -> Inspect and Transform... is selected, a popup like that shown next is seen.

I'm going to apply this new inspection to all my open projects as shown in the last screen snapshot's "Inspect" field. Clicking on the "Browse" button leads to the "Manage Inspections" window coming up as shown in the next screen snapshot.

Clicking on the "New..." button allows the developer to create a custom inspection under Custom->Inspection.

You can click the "Edit Script" button to create the custom inspection, which includes the ability to rename the inspection. I have renamed the Inspection "Unfinished Code." The next screen snapshot shows the code I added to the "Unfinished Code" inspection.

In the script code for this "Unfinished Code" inspection (which is also shown below), the description is specified as "Unfinished Code". The source pattern is specified as @dustin.examples.annotations.Unfinished($parameters$) (the entire package name of the @interface defining the custom annotation with $parameters$ indicating one or more parameters). The => symbols point to the target pattern. In this case, the target pattern is empty, indicating that the proposed transformation is to remove the @Unfinished annotation. For more details on the syntax of the NetBeans inspections editor, see Geertjan Wielenga's post Custom Declarative Hints in NetBeans IDE 7.1.

<!description="Unfinished Code">
@dustin.examples.annotations.Unfinished($parameters$)
=>
;;

With the NetBeans inspection created, it is time try it out. The next two screen snapshots demonstrate selecting that Inspection to run and the results of running it.

The output from running the inspection is an example of how we can use NetBeans in conjunction with a custom annotation to quickly identify annotated code and treat it appropriately.

Inspecting the @Unfinished Annotation in IntelliJ IDEA

One way to start creating a custom annotation in IntelliJ IDEA is to open Analyze -> Inspect Code... and click on the "..." button in the "Specify Inspection Scope" pop-up as shown in the next two screen snapshots.

The next screen snapshot shows the "Inspections" dialog box.

The screen snapshot just shown indicates that the "Structural Search Inspection" is NOT checked. Checking it (checkbox is to the right of the name "Structural Search Inspection") leads to the "Severity" level being selectable and allows a particular inspection to be added (plus sign turns from gray to green).

Clicking on the green plus sign (+), leads to two choices: "Add Search template..." or "Add Replace template...". The differentiation here is similar to NetBeans's differentiation between Source -> Inspect and Refactor -> Inspect and Transform... and I'll focus on the "Replace template" here.

When "Add Replace template..." is selected, the "Structural Replace" dialog is displayed.

The easiest way to create a custom inspection here it to adapt an existing template. This is done by clicking on the "Copy existing template..." button. For the two inspections I create for this blog post, I copied the "annotated class" and "annotated methods" existing templates respectively to create my own custom templates "Unfinished Class" and "Unfinished Method."

The screen snapshots above show the "existing templates" I copied and the screen snapshots below showed the custom templates I created from them for "Unfinished Class" and "Unfinished Method."

For each of the custom templates ("Unfinished Class" and "Unfinished Method"), I need to click on the "Edit variables..." button and specify the regular expressions for each variable (identifiers marked with $ on front and back) to be searched. For most variables (such as class name, method name, and so forth), I use an "all characters" regular representation (.*), but for the $Annotation$ in each of these templates, I use dustin.examples.annotations.Unfinished. The next screen snapshot is a representative sample of this that shows the Annotation variable setting for the "Undefined Method" template.

I can use Analyze -> Run Inspection by Name... to run either of my new inspections. The next three screen snapshots demonstrate running the new "Unfinished Method" inspection.

The output from running the inspection is an example of how we can use IntelliJ IDEA in conjunction with a custom annotation to quickly identify annotated code and treat it appropriately.

Conclusion

This post has demonstrated using NetBeans's and IntelliJ IDEA's abilities to create custom inspections to create inspections that can alert developers to the presence of custom annotations in their code. The post demonstrated a simple @Unfinished annotation and how to apply custom inspections in NetBeans and IntelliJ IDEA to help identify code that uses those annotations.

Saturday, December 27, 2014

Three Common Methods Generated in Three Java IDEs

In this post, I look at the differences in three "common" methods [equals(Object), hashCode(), and toString()] as generated by NetBeans 8.0.2, IntelliJ IDEA 14.0.2, and Eclipse Luna 4.4.1. The objective is not to determine which is best, but to show different approaches one can use for implementing these common methods. Along the way, some interesting insights can be picked up regarding creating of these common methods based on what the IDEs assume and prompt the developer to set.

NetBeans 8.0.2

NetBeans 8.0.2 allows the Project Properties to be configured to support the JDK 8 platform and to expect JDK 8 source formatting as shown in the next two screen snapshots.

Code is generated in NetBeans 8.0.2 by clicking on Source | Insert Code (or keystrokes Alt+Insert).

When generating the methods equals(Object), hashCode(), and toString(), NetBeans 8.0.2 asks for the attributes to be used in each of these generated methods as depicted in the next two screen snapshots.

The NetBeans-generated methods take advantage of the JDK 7-introduced Objects class.

NetBeans-Generated hashCode() Method for Class NetBeans802GeneratedCommonMethods.java
@Override
public int hashCode()
{
   int hash = 5;
   hash = 29 * hash + Objects.hashCode(this.someString);
   hash = 29 * hash + Objects.hashCode(this.timeUnit);
   hash = 29 * hash + this.integer;
   hash = 29 * hash + Objects.hashCode(this.longValue);
   return hash;
}
NetBeans-Generated equals(Object) Method for Class NetBeans802GeneratedCommonMethods.java
@Override
public boolean equals(Object obj)
{
   if (obj == null)
   {
      return false;
   }
   if (getClass() != obj.getClass())
   {
      return false;
   }
   final NetBeans802GeneratedCommonMethods other = (NetBeans802GeneratedCommonMethods) obj;
   if (!Objects.equals(this.someString, other.someString))
   {
      return false;
   }
   if (this.timeUnit != other.timeUnit)
   {
      return false;
   }
   if (this.integer != other.integer)
   {
      return false;
   }
   if (!Objects.equals(this.longValue, other.longValue))
   {
      return false;
   }
   return true;
}
NetBeans-Generated toString() Method for Class NetBeans802GeneratedCommonMethods.java
@Override
public String toString()
{
   return "NetBeans802GeneratedCommonMethods{" + "someString=" + someString + ", timeUnit=" + timeUnit + ", integer=" + integer + ", longValue=" + longValue + '}';
}

Some observations can be made regarding the NetBeans-generated common methods:

  • All generated code is automatic and does not support customization with the exception of the fields used in the methods which the operator selects.
  • All of these common methods that extend counterparts in the Object class automatically have the @Override annotation provided.
  • No Javadoc documentation is included for generated methods.
  • The methods make use of the Objects class to make the generated code more concise with less need for null checks.
  • Only one format is supported for the String generated by toString() and that output format is a single comma-delimited line.
  • I did not show it in the above example, but NetBeans 8.0.2's methods generation does treat arrays differently than references, enums, and primitives in some cases:
    • The generated toString() method treats array attributes of the instance like it treats other instance attributes: it relies on the array's toString(), which leads to often undesirable and typically useless results (the array's system identity hash code). It'd generally be preferable to have the string contents of array attributes provided by Arrays.toString(Object[]) or equivalent overloaded version or Arrays.deepToString(Object[]).
    • The generated hashCode() method uses Arrays.deepHashCode(Object[]) for handling arrays' hash codes.
    • The generated equals(Object) method uses Arrays.deepEquals(Object[], Object[]) for handling arrays' equality checks.
    • It is worth highlighting here that NetBeans uses the "deep" versions of the Arrays methods for comparing arrays for equality and computing arrays' hash codes while IntelliJ IDEA and Eclipse use the regular (not deep) versions of Arrays methods for comparing arrays for equality and computing arrays' hash codes.

 

IntelliJ IDEA 14.0.2

For these examples, I'm using IntelliJ IDEA 14.0.2 Community Edition.

IntelliJ IDEA 14.0.2 provides the ability to configure the Project Structure to expect a "Language Level" of JDK 8.

To generate code in IntelliJ IDEA 14.0.2, one uses the Code | Generate options (or keystrokes Alt+Insert like NetBeans).

IntelliJ IDEA 14.0.2 prompts the operator for which attributes should be included in the generated methods. It also asks which fields are non-null, meaning which fields are assumed to never be null. In the snapshot shown here, they are checked, which would lead to methods not checking those attributes for null before trying to access them. In the code that I generate with IntelliJ IDEA for this post, however, I won't have those checked, meaning that IntelliJ IDEA will check for null before accessing them in the generated methods.

IntelliJ IDEA 14.0.2's toString() generation provides a lengthy list of formats (templates) for the generated toString() method.

IntelliJ IDEA 14.0.2 also allows the operator to select the attributes to be included in the generated toString() method (selected when highlighted background is blue).

IDEA-Generated equals(Object) Method for Class Idea1402GeneratedCommonMethods.java
public boolean equals(Object o)
{
   if (this == o) return true;
   if (o == null || getClass() != o.getClass()) return false;

   Idea1402GeneratedCommonMethods that = (Idea1402GeneratedCommonMethods) o;

   if (integer != that.integer) return false;
   if (longValue != null ? !longValue.equals(that.longValue) : that.longValue != null) return false;
   if (someString != null ? !someString.equals(that.someString) : that.someString != null) return false;
   if (timeUnit != that.timeUnit) return false;

   return true;
}
IDEA-Generated hashCode() Method for Class Idea1402GeneratedCommonMethods.java
@Override
public int hashCode()
{
   int result = someString != null ? someString.hashCode() : 0;
   result = 31 * result + (timeUnit != null ? timeUnit.hashCode() : 0);
   result = 31 * result + integer;
   result = 31 * result + (longValue != null ? longValue.hashCode() : 0);
   return result;
}
IDEA-Generated toString() Method for Class Idea1402GeneratedCommonMethods.java
@Override
public String toString()
{
   return "Idea1402GeneratedCommonMethods{" +
      "someString='" + someString + '\'' +
      ", timeUnit=" + timeUnit +
      ", integer=" + integer +
      ", longValue=" + longValue +
      '}';
}

Some observations can be made regarding the IntelliJ IDEA-generated common methods:

  • Most generated code is automatic with minor available customization including the fields used in the methods which the operator selects, specification of which fields are expected to be non-null (so that null checks are not needed in generated code), and the ability to select one of eight built-in toString() formats.
  • All of these common methods that extend counterparts in the Object class automatically have the @Override annotation provided.
  • No Javadoc documentation is included for generated methods.
  • The generated methods do not make use of the Objects class and so require explicit checks for null for all references that could be null.
  • It's not shown in the above example, but IntelliJ IDEA 14.0.2 does treat arrays differently in the generation of these three common methods:

 

Eclipse Luna 4.4.1

Eclipse Luna 4.4.1 allows the Java Compiler in Project Properties to be set to JDK 8.

In Eclipse Luna, the developer uses the "Source" drop-down to select the specific type of source code generation to be performed.

Eclipse Luna allows the operator to select the attributes to be included in the common methods. It also allows the operator to specify a few characteristics of the generated methods. For example, the operator can choose to have the elements of an array printed individually in the generated toString() method rather than an often meaningless class name and system identity hash code presented.

Eclipse-Generated hashCode() Method for Class Eclipse441GeneratedCommonMethods.java
/* (non-Javadoc)
 * @see java.lang.Object#hashCode()
 */
@Override
public int hashCode()
{
   final int prime = 31;
   int result = 1;
   result = prime * result + this.integer;
   result = prime * result
         + ((this.longValue == null) ? 0 : this.longValue.hashCode());
   result = prime * result
         + ((this.someString == null) ? 0 : this.someString.hashCode());
   result = prime * result
         + ((this.timeUnit == null) ? 0 : this.timeUnit.hashCode());    return result;
}
Eclipse-Generated equals(Object) Method for Class Eclipse441GeneratedCommonMethods.java
/* (non-Javadoc)
 * @see java.lang.Object#equals(java.lang.Object)
 */
@Override
public boolean equals(Object obj)
{
   if (this == obj)
      return true;
   if (obj == null)
      return false;
   if (getClass() != obj.getClass())
      return false;
   Eclipse441GeneratedCommonMethods other = (Eclipse441GeneratedCommonMethods) obj;
   if (this.integer != other.integer)
      return false;
   if (this.longValue == null)
   {
      if (other.longValue != null)
         return false;
   } else if (!this.longValue.equals(other.longValue))
     return false;
   if (this.someString == null)
   {
      if (other.someString != null)
         return false;
   } else if (!this.someString.equals(other.someString))
      return false;
   if (this.timeUnit != other.timeUnit)
      return false;
   return true;
}
Eclipse-Generated toString() Method for Class Eclipse441GeneratedCommonMethods.java
/* (non-Javadoc)
 * @see java.lang.Object#toString()
 */
@Override
public String toString()
{
   return "Eclipse441GeneratedCommonMethods [someString=" + this.someString
         + ", timeUnit=" + this.timeUnit + ", integer=" + this.integer
         + ", longValue=" + this.longValue + "]";
}

Some observations can be made regarding the Eclipse-generated common methods:

  • Eclipse provides the most points in the generation process in which the generated output can be configured. Here are some of the configurable options:
    • Location in class (before or after existing methods of class) can be explicitly specified.
    • All of these common methods that extend counterparts in the Object class automatically have the @Override annotation provided.
    • "Method comments" can be generated, but they are not Javadoc style comments (use /* instead of /** and explicitly state they are not Javadoc comments as part of the generated comment).
    • Option to "list contents of arrays instead of using native toString()" allows developer to have Arrays.toString(Array) be used (same as IntelliJ IDEA's approach and occurs if checked) or have the system identify hash code be used (same as NetBeans's approach and occurs if not checked).
    • Support for four toString() styles plus ability to specify custom style.
    • Ability to limit the number of entries of an array, collection, or map that is printed in toString().
    • Ability to use instance of in generated equals(Object) implementation.
  • All of these common methods that extend counterparts in the Object class automatically have the @Override annotation provided.
  • The generated methods do not make use of the Objects class and so require explicit checks for null for all references that could be null.
  • Eclipse Luna 4.4.1 does treat arrays differently when generating the three common methods highlighted in this post:
    • Generated toString() optionally uses Arrays.toString(Object[]) or overloaded version for accessing contents of array.
    • Generated equals(Object) uses Arrays.equals(Object[], Object[]) or overloaded version for comparing arrays for equality.
    • Generated hashCode() uses Arrays.hashCode(Object[]) or overloaded version for computing hash code of array.
Conclusion

All three IDEs covered in this post (NetBeans, IntelliJ IDEA, and Eclipse) generate sound implementations of the common methods equals(Object), hashCode(), and toString(), but there are differences between the customizability of these generated methods across the three IDEs. The different customizations that are available and the different implementations that are generated can provide lessons for developers new to Java to learn about and consider when implementing these methods. While the most obvious and significant advantage of these IDEs' ability to generate these methods is the time savings associated with this automatic generation, other advantages of IDE generation of these methods include the ability to learn about implementing these methods and the greater likelihood of successful implementations without typos or other errors.

Tuesday, October 14, 2014

NetBeans 8.0's Five New Performance Hints

NetBeans 8.0 introduces several new Java hints. Although there are a large number of these new hints related to Java Persistence API, I focus on five new hints in the Performance category.

The five new "Performance Hints" introduced with NetBeans 8.0 are:

  • Boxing of already boxed value
  • Redundant String.toString()
  • Replace StringBuffer/StringBuilder by String
  • Unnecessary temporary during conversion from String
  • Unnecessary temporary during conversion to String

Each of these five performance-related Java hints are illustrated in this post with screen snapshots taken from NetBeans 8.0 with code that demonstrates these hints. There are two screen snapshots for each hint, one each showing the text displayed when the cursor hovers over the line of code marked with yellow underlining and one each showing the suggested course of action to be applied to address that hint (shown when clicking on the yellow light bulb to the left of the flagged line). Some of the captured screen snapshots include examples of code that avoid the hint.

Boxing of Already Boxed Value

Redundant String.toString()

Replace StringBuffer/StringBuilder by String

Unnecessary Temporary During Conversion from String

Unnecessary Temporary During Conversion to String

Unless I've done something incorrectly, there appears to be a minor bug with this hint in that it reports "Unnecessary temporary when converting from String" when, in this case, it should really be "Unnecessary temporary when converting to String". This is not a big deal as the condition is flagged and the action to fix it seems appropriate.

Conclusion

The five performance-related hints introduced by NetBeans 8.0 and illustrated here can help Java developers avoid unnecessary object instantiations and other unnecessary runtime cost. Although the benefit of this optimization as shown in my simple examples is almost negligible, it could lead to much greater savings when used in code with loops that perform these same unnecessary instantiations thousands of times. Even without consideration of the performance benefit, these hints help to remind Java developers and teach developers new to Java about the most appropriate mechanisms for acquiring instances and primitive values.