Posts tagged: Eclipse

Eclipse NEON with ANT and JRE6

Post to Twitter

This is a follow-up post for: Eclipse MARS with ANT and JRE 6 (story).

New Eclipse version, same problem. We have an updated ant plugin for you.
The plugin was created for:

Version: Neon Release (4.6.0)
Build id: 20160613-1800

Don't forget the -clean start (read the original article for more details).

Download the plugin from here. It works for us - no warranty!

Eclipse MARS with ANT and JRE 6 (story)

Post to Twitter

Eclipse Mars is available since June 25th. We didn't update our IDEs because it wasn't needed.

Some days ago we played around with JavaFXPorts Eclipse plugin. This plugin requires Eclipse Mars. So far so good. We made some tests with Mars, and everything was fine. We installed all required plugins for our internal and customer projects and configured a first workspace....
After everything was done, we tried to work with Eclipse Mars - no problems... BUT we have many projects with Java 6 compatibility.

Why Java 6?

Some big legacy projects/applications and Oracle Forms compatibility. There are more reasons, but it's not unusual to be backwards compatible, especially for frameworks and libraries!

Long story, short: It's not possible to start an ANT task with Java 6, because Java 7 is required. A nice error message appears:

JRE version less than 1.7 is not supported.

BUT it's still possible to choose any JRE in Runtime configuration dialog.
Why shouldn't it be possible to start ANT with "any" JRE?

We tried to find help in the world wide web and found some postings about our problem:

http://stackoverflow.com/questions/31052878/run-eclipse-mars-with-java-1-6
http://stackoverflow.com/questions/31808102/eclipse-mars-ant-doesnt-support-jdk-1-6-anymore

And two bug database entries:

https://bugs.eclipse.org/bugs/show_bug.cgi?id=474386
https://bugs.eclipse.org/bugs/show_bug.cgi?id=461031

It's absolutely incomprehensible why the first ticket is in state: RESOLVED INVALID and the
second one: VERIFIED FIXED.
OK, the second one was for a different requirement, but the first one explains the problem.

Why did the developer ignore the user requirement?

It's possible to call ANT with "any" JRE, without Eclipse and other IDEs don't have such crazy limitations! We didn't plan to use another IDE just for building our software!

I can't live with recommended workarounds because suggested steps were not usuable with big projects!
So, we tried to solve the problem for us. The source code of the ANT plugin is available here, so it shouldn't be a problem to "fix" the problem.

After reading source code, we found that the only reason why it's not possible to use JREs < version 7, is Java 7 Syntax:

  • Diamond operator, e.g. List<MyObject> list = new ArrayList<>();
  • try-with-resources, e.g. try (InputStream stream = createInputStream()) { ...}

And of course, the plugin was configured for execution environment JavaSE-1.7.

Our solution: Removed Java version check in class org.eclipse.ant.internal.launching.launchConfigurations.AntLaunchDelegate, method launch:

//String path = configuration.getAttribute(IJavaLaunchConfigurationConstants.ATTR_JRE_CONTAINER_PATH, new String("")); //$NON-NLS-1$
//if (!path.isEmpty()) {
//      IPath jrePath = Path.fromPortableString(path);
//      IVMInstall vm = JavaRuntime.getVMInstall(jrePath);
//      if (vm instanceof AbstractVMInstall) {
//              AbstractVMInstall install = (AbstractVMInstall) vm;
//              String vmver = install.getJavaVersion();
//              // versionToJdkLevel only handles 3 char versions = 1.5, 1.6, 1.9, etc
//              if (vmver.length() > 3) {
//                      vmver = vmver.substring(0, 3);
//              }
//              int ver = (int) (CompilerOptions.versionToJdkLevel(vmver) >>> 16);
//              if (ver < ClassFileConstants.MAJOR_VERSION_1_7) {
//                      // IStatus status = new Status(IStatus.ERROR, AntLaunching.PLUGIN_ID, 1,
//                      // AntLaunchConfigurationMessages.AntLaunchDelegate_Launching__0__2, null);
//                      // throw new CoreException(status);
//              }
//      }
//}

We set the execution environment for org.eclipse.ant.launching, org.eclipse.ant.core and org.eclipse.ant.ui to JavaSE-1.6 and made the source code compatible with Java 6 syntax.

After we built the required jar files, we had problems with Eclipse, because there was something like a plugin cache (not sure what exactly). We made a test with -clean command line parameter and were happy. It was possible to start ANT tasks - with JRE 6 - without modifications, directly via Eclipse.

It's not difficult to create your own ANT plugin, but here are our jar files.
The libs were built for

Version: Mars Release (4.5.0)
Build id: 20150621-1200

The tag-id of the ANT plugin source code: I20150430-1445.

Installation?

  • Download the zip archive, extract the content to <eclipse_dir>/plugins.
  • Start eclipse with parameter -clean (only once)
  • Configure JRE6 for your ANT task, via Externals Tool configuration...

Feel free to use our changed files but we don't guarantee that it doesn't destroy your Eclipse Mars installation :)
We didn't have any problems so far, but send us your impressions.

We didn't publish the changed source code right now, but let us know if you need it - it's still under EPL.

JavaFXPorts with Eclipse

Post to Twitter

Some weeks ago, Gluon released the first version of their Eclipse plugin for creating/building mobile applications with Java(FX).

We had some experience with their NetBeans plugin but our preferred IDE was Eclipse. So, an Eclipse plugin was good for us :)
The NetBeans version worked without bigger problems and we expected the same quality for the Eclipse plugin.

We followed the official installation instructions and didn't have any problem. But the problems started after we tried to create Android or iOS specific code. It wasn't possible to access javafxports, android or robovm classes, because the jar files weren't found. The classpath with NetBeans had references to all libraries, but the Eclipse project didn't have such references.

We tried to find some information in the documentation and found the NFC example application. The build file had additional dependencies for android and javafxports. We changed the build file of our Eclipse project:

dependencies {
    compile files("C:/tools/android/android-sdk_r04-windows/platforms/android-21/android.jar")
    compile "org.javafxports:jfxdvk:8u60-b3"
       
    compile fileTree(dir: 'libs', include: '*.jar')
    runtime fileTree(dir: 'libs', include: '*.jar')
}

and after some Gradle/Refresh Dependencies, Refresh All clicks, all Errors were fixed!
It was horrible, because after clicking Refresh Dependencies, nothing happened and after some more clicks, all errors were gone. Not sure if this was a Gradle project problem, or Gluon plugin problem.

Our full build script (without robovm):

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'org.javafxports:jfxmobile-plugin:1.0.1'

    }
}

apply plugin: 'org.javafxports.jfxmobile'

repositories {
    jcenter()
}

dependencies {
    compile files("C:/tools/android/android-sdk_r04-windows/platforms/android-21/android.jar")
    compile "org.javafxports:jfxdvk:8u60-b3"
       
    compile fileTree(dir: 'libs', include: '*.jar')
    runtime fileTree(dir: 'libs', include: '*.jar')
}

mainClassName = 'com.sibvisions.mobilefx.android.DemoERPApplication'
   
jfxmobile {
    ios {
        forceLinkClasses = [ 'com.sibvisions.mobilefx.ios.**.*' ]
    }
   
    android {
      androidSdk = 'C:/tools/android/android-sdk_r04-windows'
      compileSdkVersion = 21  
    }
}

Hints
  • Enable developer options for your Android device
  • Show log messages from your Android device: \platform-tools\adb logcat

EPlug 1.2.0

Post to Twitter

Great news for everyone who uses, or plans to use our Eclipse plugin called EPlug, a new version  is available! Version 1.2.0 brings a whole truckload of new features and bug fixes.

Changes (Pro and VisionX)

  • Completion for resources is now more reliable
  • Sped up the time it takes for VisionX to reload a file if a change was made in Eclipse
  • MetaData changes are now properly handled
  • When selecting from VisionX to Eclipse it will be made sure that the server and client class both show up
  • Added the "Checkl File (EPlug)" command, which allows to easily re-run all checks on the current file
  • The hyperlinks for server calls/actions are now "fuzzy", which means that if there is no function with that signature, the next best function will be the target
  • Improved the error messages if there was a problem when checking databooks
  • Added completion for generic resources, which means you now can get completion for any resource in your project
  • The call to UIImage.getImage(String) is now checked at compile time if the resource exists
  • By default, databooks are now checked while you're typing for instant feedback. This can be disabled in the project properties
  • Added a view that displays all databooks in the current file, including column name and type
  • Added support for the constructor of UIEditor
  • Dramatically increased the speed of compile time checks

Eclipse Mars

Also we have tested and developed EPlug with Eclipse Mars, which means that you can use it in the latest and greatest Eclipse release version. Of course we haven't dropped support for older versions, EPlug should continue to work even on Eclipse Juno.

Download

You can install EPlug directly from the Eclipse Marketplace.

EPlug - The Big Guided Tour

Post to Twitter

Since last year we are offering an Eclipse Plugin that integrates  the JVx workflow into Eclipse. Now that EPlug 1.2 has been released, we believe it's long overdue to give you a guided tour of the experience that EPlug is offering.

Trial

We offer a free trial period so that you can test EPlug without any problems. The first time you start Eclipse with EPlug you will be asked if you'd like to only test EPlug, or if you'd like to select an already purchased Pro license.

Showing the EPlug license welcome screen.

When clicking the Trial button, a new trial license will be issued and you'll be able to evaluate EPlug with all features for 30 days.

Showing the trial window.

'First Run' Wizard

One of the biggest usability improvements compared to previous versions is discoverability of how to use and activate EPlug. With the new version we have added a "First Run Wizard" which allows to directly activate EPlug on selected projects.

First Run Wizard

Usage

EPlug integrates seamlessly into Eclipse, but to use most of its features it has to be activated on each project you want to use it with. This can be done in the previously shown First Run Wizard, or by right-clicking a project and selecting "Activate EPlug" under "Configure".

Showing how to activate EPlug.

From there on you will be able to use code completion, compile time checks and all the other features on this project.

Better and extended commands

A handful of commands are added by EPlug, which make it faster to navigate in JVx projects.

Go to complement class

It's often the case that you want to go from the server to the client class, or from the client to the server class. Most of the time in Eclipse this involves expanding trees and looking for the correct class in the Package Explorer. That is why we've implement the command "Go to complement class", which enables you to quickly jump from the server to client, or the other way round.

The context menu of Eclipse showing the "Go to complement class".

As you can see the command is available from the context menu, but you can also bind it to a key in the "Keys" preferences.

Showing the motion of the command.

Open Declaration

The "Open Declaration" command, sometimes known by its key binding "F3", allows you to jump to the declaration of whatever is currently under the cursor. We've extended this command with the possibility to jump to the declaration of event handlers (actions), server methods and storage's. If the item underneath the cursor is not handled by our extension, the default "Open Declaration" command will be invoked.

The context menu of Eclipse showing the "Open Declaration (EPlug)" command.

The declaration:

Showing the target of the command.

Because we've extended the "Open Declaration" command, you can bind the "Open Declaration (EPlug)" command also to "F3" and enjoy faster navigating in your JVx files without any downsides.

DataBooks

The biggest and most important feature of EPlug is its support for data books. EPlug offers code completion, compile time checks and more for column names on remote and local data books.

Code completion

Everytime you want to get or set a value, or wire up an editor you will receive code completion suggestions with all column names that are in the databook, it doesn't matter if those are remote or added locally.

Showing the code completion of columns.

Compile time checks

Of course we also added compile time checks, which means that you can never mistype a column name ever again.

Showing the compile time checks of column names.

With the newest version, these compile time checks are even active while you type!

Text hovers

When hovering above a column name, a simple text hover will inform you about the type of the column.

Showing the text hovers of columns.

Storage support

RemoteDataBooks require to have the correct name set so that the server side storage is found, of course we do also offer code completion, compile time checks, text hovers and hyperlinks for this.

Showing the code completion for storages.

Showing the compile time checks of storages.

The DataBook View

And last but for sure not least, with the newest version a feature has been added which I've been looking forward to for quite some time: The DataBook View. A view similar to the Outline view, which displays all databooks in the current file and all of its columns.

Showing the DataBookView.

Actions/Events and server calls

Support for actions, events and server calls is the second big EPlug feature. For events and actions we support a very Lambda-like system that uses reflection and strings. Obviously the compiler was never able to understand this system and provide feedback or support for it, but with EPlug this has changed.

Code Completion

Whenever you want to wire up an event, you'll now receive code completion for all fitting methods in the used class.

Action methods:

Showing the code completion for events.

Remote calls:

Showing the code completion for server calls.

As you can see in upper image, we also provide a fast and convenient way to create methods if necessary.

Compile time checks

During compilation the actions, events and server calls are checked for their correctness, and if there is a problem it'll be reported to you.

Showing the compile time checks of actions.

You can also see the quick fixes for this problem, which do not only offer to create the missing method, but also suggesting methods with similar names in case a typo happened.

Text hovers, hyperlinks and refactoring support

Additionally EPlug provides text hover and hyperlink support, that means that you can now jump to the methods by using your mouse (Ctrl+Left Click) or the "Open Declaration (EPlug)" command. Refactoring support has also been added, which means that you can now rename action/event handlers without having to manually search for all uses and change those.

Resources

Dealing with resources can often be a pain in the neck, especially if you constantly have to look up the path and check if you're now using the correct image. Because we also felt these pains, we've added functionality to EPlug to make sure that working with resources becomes easy and painless.

Support for UIImage

Whenever you use UIImage methods, you can now enjoy code completion, previews of the images and compile time checks.

Showing the code completion for UIImage.

Preview:

Showing the preview of images in UIImage.

Compile checks:

Compile time checks of resources.

Generic resource completion

For all other resources, we do only offer a "generic" code completion system and no preview. Still, this is a huge help.

Showing the code completion for other resources.

Comments

One of the more simple and not so obvious features of EPlug is that it allows to have code completion of the current class in comments, and also provides the JVx category separators.

Showing the code completion for comments.

Separator:

Showing the code completion for comments.

Action/call completion in comments:

Showing the code completion for comments.

VisionX support

Now we've arrive at the big final, support for VisionX. For all of you who do not know VisionX, it is our product for rapidly building applications from scratch or migrating already existing systems. It allows to build GUIs and the respective database backend within a matter of minutes. Even though VisionX allows you to build whole applications, from time to time you'll want to do something by hand and this is the great thing about VisionX, all projects and applications are automatically and by design already Eclipse projects. So all you need to do is import the project into Eclipse and start working on it. To improve this workflow further EPlug does offer various features.

Selection synchronization

The selection in Eclipse and VisionX can be automatically synchronized, so that whatever you're working on in the one application is also visible and selected in the other

Showing the selection between VisionX and Eclipse.

Automatic applying of changes

VisionX will also automatically refresh its current view if you change a sourcefile in Eclipse, allowing to rapidly and verify changes in a workscreen without the need to manually reload the workscreen.

How and where to get it?

EPlug comes in two flavors, EPlug for JVx and EPlug for VisionX, both are available from the Eclipse Marketplace and can be installed and used freely for 30 days. Afterwards a license is necessary to keep using all features.

VisionX RnD news - IDE integration

Post to Twitter

We want to tell you some fantastic news from our RnD team: The next big step for VisionX will be an IDE integration feature.

Our team is working very hard to reach the goals. The result will be an Eclipse plugin that connects to VisionX and allows bidirectional communication. We won't embedd VisionX in Eclipse because it makes no sense for us, but we'll use the whole power of the IDE.

What will be supported?

  • Event links (Eclipse)

    A click on an event action string will jump to the right method.

    databook.eventValuesChanged().addListener(this, "doValuesChanged");

    The click on doValuesChanged will jump to the method in the work-screen.

  • Call links (Eclipse)

    A click on an action/object call will jump to the right method, in the right life-cycle object.

    getConnection().callAction("getLicenseInformation");

    The click on getLicenseInformation will jump to the method in the life-cycle object.

  • DataBook links (Eclipse)

    A click on the name of a databook will jump to the storage definition, in the life-cycle object.

    RemoteDataBook rdb = new RemoteDataBook();
    rdb.setDataSource(dataSource);
    rdb.setName("users");
    rdb.open();

    The click on users will jump to the DBStorage definition, in the the life-cycle object.

  • Auto completion (Eclipse)

    We'll offer auto completion for table columns, event methods, action/object calls, ...

    databook.getRowDefinition().getColumnDefinition("DESCRIPTION").getDataType().setCellEditor(VisionXUtil.MULTILINE_EDITOR);

    It'll be possible to get a list of all available columns, like DESCRIPTION.

  • Column checks (Eclipse)

    We'll check if all column names are valid and will show compiler warnings/errors.

  • Jump to Eclipse

    It'll be possible, with VisionX, to jump to the source code of e.g. actions, component definitions or databooks in Eclipse. We'll introduce some new Buttons in VisionX, for that feature.

    VisionX E-Plug

    VisionX E-Plug

  • Jump to VisionX

    It'll be possible, with Eclipse, to highlight selected GUI components directly in VisionX.

No worries, we have more features for you!

The IDE integration will be available as optional VisionX module.

Source Code modification with Eclipse AST

Post to Twitter

We heavily use Eclipse AST and JDT. The problem with both APIs is that you don't find a lot of documentation or examples. The best documentation was and is the source code. It shows all secrets.

Last friday at Eclipse DemoCamp Vienna, I discussed with CodeCop about AST and JDT and the missing documentation :)

I wrote a simple class for class/superclass/package/javadoc manipulation some months ago. It is included in VisionX and is not free, but no matter. Here is the source code:

/*
(c) SIB Visions 2012

http://www.sibvisions.com
*/
public class SimpleSourceFile {
    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    // Class members
    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    /** the source parser. */
    private ASTParser parser;

    /** the parsed tokens of the source file. */
    private CompilationUnit cuSource;

    /** the original document. */
    private Document docOrig;

    /** the class type info. */
    private TypeDeclaration tdClass;

    /** the javadoc of the class. */
    private JavadocInfo jdoc;

    /** the full qualified name of the class. */
    private String sClassName;

    /** the full qualified name of the super class after loading. */
    private String sLoadedSuperClass;

    /** the full qualified name of the parent class. */
    private String sSuperClass;

    /** whether the source is changed. */
    private boolean bChanged = false;

    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    // Initialization
    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    /**
     * Creates a new instance of <code>SimpleSourceFile</code> without source
     * information.
     */

    public SimpleSourceFile() {
        load("");
    }

    /**
     * Creates a new instance of <code>SimpleSourceFile</code> with a given
     * source file.
     *  
     * @param pFile the java source file
     * @throws IOException if an error occurs during reading the file
     */

    public SimpleSourceFile(File pFile) throws IOException {
        if (pFile.exists()) {
            JavaSource source = JavaSource.get(pFile.getAbsolutePath());

            if (source != null) {
                synchronized(source) {
                    load(new String(FileUtil.getContent(pFile)));
                }
            } else {
                load(new String(FileUtil.getContent(pFile)));
            }
        } else {
            load("");
        }
    }

    /**
     * Creates a new instance of <code>SimpleSourceFile</code> with a given
     * source stream. The stream is closed after reading
     *  
     * @param pStream the java source stream
     * @throws IOException if an error occurs during reading the stream
     */

    public SimpleSourceFile(InputStream pStream) throws IOException {
        this(pStream, true);
    }

    /**
     * Creates a new instance of <code>SimpleSourceFile</code> with a given
     * source stream.
     *  
     * @param pStream the java source stream
     * @param pAutoClose whether the stream should be closed after reading
     * @throws IOException if an error occurs during reading the stream
     */

    public SimpleSourceFile(InputStream pStream, boolean pAutoClose) throws IOException {
        load(new String(FileUtil.getContent(pStream, pAutoClose)));
    }

    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    // User-defined methods
    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    /**
     * Loads the properties from the source file.
     *
     * @param pSource the java source
     */
@SuppressWarnings({
        "unchecked", "rawtypes"
    })
    private void load(String pSource) {
        jdoc = new JavadocInfo();

        if (parser == null) {
            parser = ASTUtil.createParser();
        }

        parser.setSource(pSource.toCharArray());

        cuSource = (CompilationUnit) parser.createAST(null);

        if (docOrig != null) {
            docOrig.set(pSource);
        } else {
            docOrig = new Document(pSource);
        }

        //we support only one class per file
        List types = cuSource.types();

        if (types.size() > 0 && types.get(0) instanceof TypeDeclaration) {
            tdClass = (TypeDeclaration) types.get(0);

            String sPackage;

            //we have to use the current package, if set
            if (cuSource.getPackage() != null) {
                sPackage = cuSource.getPackage().getName().getFullyQualifiedName() + ".";
            } else {
                sPackage = "";
            }

            sClassName = sPackage + tdClass.getName().getFullyQualifiedName();

            if (tdClass.getSuperclassType() != null) {
                String sSuperName = ((SimpleType)(tdClass.getSuperclassType())).getName().getFullyQualifiedName();

                if (sSuperName.indexOf('.') > 0) {
                    sSuperClass = sSuperName;
                } else {
                    //try to detect the full qualified name of the super class through the imports

                    List < ImportDeclaration > liImports = cuSource.imports();

                    boolean bFound = false;

                    if (liImports != null) {
                        String sTempName = "." + sSuperName;
                        String sImport;

                        for (int i = 0, anz = liImports.size(); !bFound && i < anz; i++) {
                            sImport = liImports.get(i).getName().getFullyQualifiedName();
                            if (sImport.endsWith(sTempName)) {
                                bFound = true;

                                sSuperClass = liImports.get(i).getName().getFullyQualifiedName();
                            }
                        }
                    }

                    if (!bFound) {
                        //we use the current package
                       sSuperClass = sPackage + sSuperName;
                    }
                }

                //cache for optimizing imports in apply
                sLoadedSuperClass = sSuperClass;
            }

            jdoc = new JavadocInfo(tdClass.getJavadoc(), pSource);
        } else {
            tdClass = null;
        }

        //currently loaded file can not be changed!
        bChanged = false;
    }

    /**
     * Sets the comment for the class.
     *
     * @param pText the comment
     */

    public void setClassComment(String pText) {
        bChanged |= !CommonUtil.equals(pText, jdoc.getDescription());

        jdoc.setDescription(pText);
    }

    /**
     * Gets the comment for the class.
     *
     * @return the comment
     */

    public String getClassComment() {
        return jdoc.getDescription();
    }

    /**
     * Sets the full qualified name of the class.
     *
     * @param pName the class name
     */

    public void setClassName(String pName) {
        if (pName == null) {
            throw new IllegalArgumentException("It is not allowed to remove the class definition (class name = null)!");
        }

        bChanged |= !CommonUtil.equals(pName, sClassName);

        sClassName = pName;
    }

    /**
     * Gets the full qualified name of the class.
     *
     * @return the class name
     */

    public String getClassName() {
        return sClassName;
    }

    /**
     * Sets the full qualified class name of the parent class.
     *
     * @param pSuperClass the full qualified class name of the parent class
     */

    public void setSuperClass(String pSuperClass) {
        bChanged |= !CommonUtil.equals(pSuperClass, sSuperClass);

        sSuperClass = pSuperClass;
    }

    /**
     * Gets the full qualified class name of the parent class.
     *
     * @return the class name
     */

    public String getSuperClass() {
        return sSuperClass;
    }

    /**
     * Replaces the relevant information with the specific values
     * and saves the source file.
     *
     * @throws Exception if the source modification fails
     */
@SuppressWarnings("unchecked")
    protected void apply() throws Exception {
        if (!bChanged) {
            return;
        }

        AST ast = cuSource.getAST();

        ASTRewrite arw = ASTRewrite.create(ast);

        //----------------------------------------------------
        // Change Package, Classname and Constructor
        //----------------------------------------------------

        String sCurrentPackage;

        //set package
        String[] sClassInfo = ClassUtil.splitName(sClassName);

        if (sClassInfo[0] != null) {
            if (cuSource.getPackage() != null) {
                arw.set(cuSource.getPackage(), PackageDeclaration.NAME_PROPERTY, ast.newName(sClassInfo[0]), null);

                sCurrentPackage = sClassInfo[0];
            } else {
                PackageDeclaration pdcl = ast.newPackageDeclaration();
                pdcl.setName(ast.newName(sClassInfo[0]));

                arw.set(cuSource, CompilationUnit.PACKAGE_PROPERTY, pdcl, null);

                sCurrentPackage = sClassInfo[0];
            }
        } else {
            arw.set(cuSource, CompilationUnit.PACKAGE_PROPERTY, null, null);

            sCurrentPackage = null;
        }

        if (tdClass == null) {
            //new class
            tdClass = ast.newTypeDeclaration();
            tdClass.setName(ast.newSimpleName(sClassInfo[1]));

            ListRewrite lrwImp = arw.getListRewrite(cuSource, CompilationUnit.TYPES_PROPERTY);
            lrwImp.insertFirst(tdClass, null);
        } else {
            //change class name
            SimpleName snClass = ast.newSimpleName(sClassInfo[1]);

            arw.set(tdClass, TypeDeclaration.NAME_PROPERTY, snClass, null);

            //chage constructors

            MethodDeclaration[] methods = tdClass.getMethods();

            if (methods != null) {
                for (MethodDeclaration method: methods) {
                    if (method.isConstructor()) {
                        arw.set(method, MethodDeclaration.NAME_PROPERTY, snClass, null);
                    }
                }
            }
        }

        //change Superclass

        List < ImportDeclaration > liImports = cuSource.imports();

        //remove "old" import
       if (sLoadedSuperClass != null) {
            if (liImports != null) {
                boolean bFound = false;

                for (int i = liImports.size() - 1; !bFound && i >= 0; i--) {
                    if (sLoadedSuperClass.equals(liImports.get(i).getName().getFullyQualifiedName())) {
                        bFound = true;

                        arw.remove(liImports.get(i), null);

                        liImports.remove(i);
                    }
                }
            }
        }

        if (sSuperClass == null) {
            arw.set(tdClass, TypeDeclaration.SUPERCLASS_TYPE_PROPERTY, null, null);
        } else {
            //check new super class import
            String[] sSuperClassInfo = ClassUtil.splitName(sSuperClass);

            if (sSuperClassInfo[0] != null) {
                boolean bFound = false;

                if (sCurrentPackage != null) {
                    bFound = sSuperClassInfo[0].equals(sCurrentPackage);
                }

                if (!bFound) {
                    if (liImports != null) {
                        for (int i = 0, anz = liImports.size(); !bFound && i < anz; i++) {
                            bFound = sSuperClass.equals(liImports.get(i).getName().getFullyQualifiedName());
                        }
                    }
                }

                //class not already importet -> add import
               if (!bFound) {
                    ImportDeclaration idSuper = ast.newImportDeclaration();
                    idSuper.setName(ast.newName(sSuperClass));

                    ListRewrite lrwImp = arw.getListRewrite(cuSource, CompilationUnit.IMPORTS_PROPERTY);
                    lrwImp.insertLast(idSuper, null);
                }
            }

            arw.set(tdClass, TypeDeclaration.SUPERCLASS_TYPE_PROPERTY, ast.newSimpleType(ast.newName(sSuperClassInfo[1])), null);
        }

        //----------------------------------------------------
        // Change Javadoc of the class
        //----------------------------------------------------

        if ("".equals(jdoc.toString())) {
            //no javadoc
            arw.set(tdClass, TypeDeclaration.JAVADOC_PROPERTY, null, null);
        } else {
            arw.set(tdClass, TypeDeclaration.JAVADOC_PROPERTY, jdoc.createJavadoc(tdClass.getAST()), null);
        }

        //----------------------------------------------------
        // Modify AST
        //----------------------------------------------------

        TextEdit edit = arw.rewriteAST(docOrig, null);
        edit.apply(docOrig);

        ASTUtil.applyFormat(docOrig);

        //simple reparse (important for the comments)
        parser.setSource(docOrig.get().toCharArray());

        cuSource = (CompilationUnit) parser.createAST(null);

        //----------------------------------------------------
        // Modify comments
        //----------------------------------------------------

        //Class comment after the last bracket

        int iCorr = 0;

        List < Comment > liComments = cuSource.getCommentList();

        if (liComments != null) {
            String sOldName = tdClass.getName().getFullyQualifiedName();
            String sText;

            for (Comment com: liComments) {
                sText = docOrig.get(com.getStartPosition() - iCorr, com.getLength());

                int iPos = 0;
                int iClassLen = sClassInfo[1].length();
                int iLenDiff = sOldName.length() - iClassLen;

                int iNextPos;

                CharacterType ctypePrev;
                CharacterType ctypeNext;

                while ((iPos = sText.indexOf(sOldName, iPos)) >= 0) {
                    if (iPos > 0) {
                        ctypePrev = StringUtil.getCharacterType("" + sText.charAt(iPos - 1));
                    } else {
                        ctypePrev = CharacterType.OnlySpecial;
                    }

                    iNextPos = iPos + sOldName.length();

                    if (iNextPos <= sText.length() - 1) {
                        ctypeNext = StringUtil.getCharacterType("" + sText.charAt(iNextPos));
                    } else {
                        ctypeNext = CharacterType.OnlySpecial;
                    }

                    //don't replace word parts e.g. ContactsWorkScreen should not be replaced with Contacts
                    if ((ctypePrev == CharacterType.OnlySpecial || ctypePrev == CharacterType.OnlyWhitespace) && (ctypeNext == CharacterType.OnlySpecial || ctypeNext == CharacterType.OnlyWhitespace)) {
                        docOrig.replace(com.getStartPosition() + iPos - iCorr, sOldName.length(), sClassInfo[1]);

                        iCorr += iLenDiff;
                        iPos += iClassLen;
                    } else {
                        iPos = iNextPos;
                    }
                }
            }
        }

        //----------------------------------------------------
        // Update
        //----------------------------------------------------

        load(docOrig.get());

        bChanged = false;
    }

    /**
     * Stores the changed source into the given file.
     *
     * @param pFile the target file for the source
     * @throws Exception if an error occurs during saving
     */

    public void saveAs(File pFile) throws Exception {
        apply();

        JavaSource source = JavaSource.get(pFile.getAbsolutePath());

        if (source != null) {
            synchronized(source) {
                FileUtil.save(pFile, docOrig.get().getBytes());

                source.reload();
            }
        } else {
            FileUtil.save(pFile, docOrig.get().getBytes());
        }
    }

    /**
     * Stores the changed source into the given stream.
     *
     * @param pStream the target stream for the source
     * @throws Exception if an error occurs during saving
     */

    public void saveAs(OutputStream pStream) throws Exception {
        apply();

        pStream.write(docOrig.get().getBytes());
        pStream.flush();
    }

    /**
     * Returns the modified source code.
     *  
     * @return the modified source code
     * @throws Exception if the source modification fails
     */

    protected String getSource() throws Exception {
        apply();

        return docOrig.get();
    }

} // SimpleSourceFile

Important imports:

import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.core.dom.ASTParser;
import org.eclipse.jdt.core.dom.Comment;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.ImportDeclaration;
import org.eclipse.jdt.core.dom.MethodDeclaration;
import org.eclipse.jdt.core.dom.PackageDeclaration;
import org.eclipse.jdt.core.dom.SimpleName;
import org.eclipse.jdt.core.dom.SimpleType;
import org.eclipse.jdt.core.dom.TypeDeclaration;
import org.eclipse.jdt.core.dom.rewrite.ASTRewrite;
import org.eclipse.jdt.core.dom.rewrite.ListRewrite;
import org.eclipse.jface.text.Document;
import org.eclipse.text.edits.TextEdit;

The class contains references to other classes like CommonUtil, FileUtil, StringUtil. These classes are included in JVx. There are two classes (JavaSource, ClassUtil) that are not free, but you should find out how it works without these classes.

If you'll set a new superclass, the superclass and its import, if available, will be updated. If you'll set a new classname, all constructors will be updated.

And once again: The best documentation is the source code :)

SIB Visions Eclipse Update Site

Post to Twitter

Use the following URL to install SIB Visions Eclipse Plug-ins:

http://eclipse.sibvisions.com/update

The above URL is the official SIB Visions Eclipse Updatesite.