Created at:

Modified at:

Java notes

Last update to this page ocurred on 2018-06-15.

Developing a Java EE application without an IDE

(2017-04-23)

With Java popularity, Java IDEs also arose as "de facto" standards for Java development. NetBeans and Eclipse emerged as the most known IDEs in the Java world and later have added support for other languages.

NetBeans

Eclipse

Companies have standardized those (or other) IDEs as the unique development environment developers could use, to the detriment of other tools like simple text editors (Vim or Emacs) and, sometimes, have prohibit developers to use tools other than the IDE they have chosen. IDEs also provide a tight integration with other tools (compilers, deploy tools, source code review, etc.) that makes it difficult for text editors users to know how to to integrate than besides the traditional way (editor + Makefile).

Vim

Emacs

The idea of this section is to document my experience regarding using a project developed in Eclipse using nothing more than Vim and command line tools to build and making a full deploy of a Java EE (.ear) application. I believe that the procedure may be similar for NetBeans or other IDEs.

The scenario

My scenario is: I started to work in a relatively small team with around 8 developers developing a Java EE application with around 1 million of lines of code. The code base was bought from another company and all of it was developed from Eclipse. The (poor) documentation was fully written taking Eclipse as a starting point and all related tools are integrated with Eclipse. Want to generate a simple EAR file? You need Eclipse. Want to run JBoss to show up your application? You need to open Eclipse and launch JBoss from there.

The application we were developing was heavy. It spawns dozens of threads on startup, it used lots of different frameworks and it needs at least 4 GB to run basic features. Worse: JBoss and Java are itself bloated stuff that made things worse. How someone could still use Eclipse in this environment? We cannot get rid of the application or JBoss, but we can get rid of Eclipse.

To get things worse, all developers used either Microsoft Windows or Ubuntu GNu/Linux, which Eclipse supports, but I used NetBSD.

NetBSD

The procedure to eliminate Eclipse and use Apache Ant to compile the project

First of all, Eclipse does not use the javac compiler that you will find in a plain JDK installation. It uses its own compiler called *Eclipse Compiler for Java* (ECJ) and they do that because of tighter integration with the IDE (see the following link for more details).

What is the difference between javac and the Eclipse compiler?

For a reason I don't remember, I couldn't use the javac compiler that comes with JDK. So I had to use Eclipse compiler. Because of that, you will need to copy Eclipse plugins directory anywhere, where package org.clipse.jdt.core.* and dependencies belong to. To avoid dependency problems, I copied the full plugins directory. In this example, it was copied to /opt/eclipse-kepler-plugins (yes, it is a past version of Eclipse but it is what the team is using).

Eclipse also builds the project automatically, without a explicit build file (like a Makefile or Apache Ant build.xml). Since we will build the project manually after editing files in the text editor, we will need to generate this script. This is an Apache Ant script. To generate that, in Eclipse, click the *File* menu, and then *Export*. Chose option *Ant build file* and export it. It will generate a file build.xml.

Apache Ant

*Note:* Since I didn't want to install Eclipse just to generate this file, I asked one of my colleagues to generate it for me.

*Note:* In the project we were working on, there was already a build.xml file used to generate EAR files. Because of that I exported to a different name, make.xml and had to explicitly pass its name to ant as ant -f make.xml.

So, after generating the build.xml file, you'll need to add a line to it, specifying that you are going to use the Eclipse compiler. According to article linked below you just need to include the following line just before the <javac ...>.

Running Eclipse Java Compiler with Ant

Example:

    <property name="build.compiler" value="org.eclipse.jdt.core.JDTCompilerAdapter" />

An important thing is to add the JAR files of the eclipse plugins directory to your class path. It can be done within the build.xml file. In your project's <path ...> tag, add it:

    <fileset dir="/opt/eclipse-kepler-plugins" includes="*.jar"/>

It may be enough! A call to ant should now compile every .java file and generate .class files. Minor tweaking may be necessary in build.xml to match your system configuration.

*Note*: How to generate .ear files is beyond the scope of this text, since there was a separated ant file in the project that did that and I just called it, never needing to see how it worked.

Deleting blank paragraphs when generating reports with XDocReport

(2017-09-20)

XDocReport_ is a great solution developed by Angelo Zerr for those who want to escape from unflexible report solutions like Jasper Reports. XDocReports allows users to develop their own reports with LibreOffice or Microsoft Office using a Freemarker or Velocity template engines. The speciall advantage of it is that it doesn't require the user to have deep programming knowledge to develop the reports (of course the backend Java code might provide a user interface to allow users to easily plug in their reports to the solution).

XDocReport

Angelo Zerr

Jasper Reports

Freemarker

Velocity

A problem with XDocReport, though, is that some preprocessed lines are expanded to blank paragraphs (or blank lines). At the time I write this (although we are in 2017, we are using XDocReport 1.0.6 by 2016) , it is a feature request (see issue 445 linked below) and there have been discussed in a xdocreport Google Groups entry (linked below). It is not a easy problem to address without adding more syntax to the reports.

xdocreport not removing Paragraphs after mail merge when field value is empty or condition not match

xdocreport Google Groups entry: @removeLine?

I decided to implement my own @removeLine feature based on the Google Groups discussion. The user have to add @removeLine string on every blank line or line that will expand to a blank line. I process the report passing a ByteArrayOutputStream as output::

ByteArrayOutputStream out = new ByteArrayOutputStream(); report.process(context, out);

*Important*: The Java code we show here is of version 1.6 in a legacy system, full of problems. I'd like to update and fix it, but unfortunatelly I don't have this time. Watch out for bad code!

Than, instead of writing the ByteArrayOutputStream to a file, obtaining the result in a ODT file (we are working with ODT here) we are going to manipulate it a little more::

     ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
     IOUtils.copy(in, out);
     in.reset();

     XDocArchive xdocarchive = XDocArchive.readZip(in);
     xdocarchive = removeLines(xdocarchive);

     HttpServletResponse r = getCurrentResponse();
     ServletOutputStream outservlet = r.getOutputStream();
     r.setContentType("application/odt");
     r.addHeader("Content-Disposition", "attachment; filename=report.odt");

     XDocArchive.writeZip(xdocarchive, outservlet);

We showed that we are sending the result HTTP but the import thing about this snippet is that we pass the xdocarchive object (of type XDocArchive) to the removeLines() and removeXMLNodes() methods, where important thing happens. Let's see how it works::

    private static void removeXMLNodes(Node elem, String xpathstr) {
            XPathFactory xpf = XPathFactory.newInstance();
            XPath xpath = xpf.newXPath();
            try {
                    XPathExpression e = xpath.compile(xpathstr);
                    NodeList nodes = (NodeList) e.evaluate(elem, XPathConstants.NODESET);
                    for (int i = 0; i < nodes.getLength(); i++) {
                            Node node = nodes.item(i);
                            Node parent = node.getParentNode();
                            parent.removeChild(node);
                    }
            } catch (Exception e) {
                    e.printStackTrace();
            }
    }

    private XDocArchive removeLines(XDocArchive xdocarchive) throws IOException, SAXException, TransformerException, ParserConfigurationException {
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            DocumentBuilder builder = factory.newDocumentBuilder();

            /* Convert InputStream to ByteOutputStream */
            byte[] buf = new byte[8192];
            int bytesRead = 0;
            ByteArrayOutputStream out_barray = new ByteArrayOutputStream();
            InputStream in = xdocarchive.getEntryInputStream("content.xml");
            while ((bytesRead = in.read(buf)) != -1) {
                    out_barray.write(buf, 0, bytesRead);
            }
            in.close();

            /* Now convert ByteArrayOutputStream to ByteArrayInputStream */
            byte[] data = out_barray.toByteArray();
            ByteArrayInputStream in_barray = new ByteArrayInputStream(data);

            Document document = builder.parse(in_barray);

            /* Remove all paragraphs that have *only* text "@removeLine". */
            removeXMLNodes( document, "//*[name() = 'text:p' and . = '@removeLine']");

            OutputStream out_after_removelines = xdocarchive.getEntryOutputStream("content.xml");
            String str;

            /*
             * XXX: 
             * Code below should be written this:
             *
             *     DOMImplementationLS domImplementation = (DOMImplementationLS) document.getImplementation();
             *     LSSerializer lsSerializer = domImplementation.createLSSerializer();
             *     str = lsSerializer.writeToString(document);
             *
             * But, for any reason I don't know, I'm getting this error:
             *
             *     16:07:19,205 SEVERE [application] java.lang.NoSuchMethodError: org.apache.xml.serializer.Serializer.asDOM3Serializer()Ljava/lang/Object;
             *     javax.faces.el.EvaluationException: java.lang.NoSuchMethodError: org.apache.xml.serializer.Serializer.asDOM3Serializer()Ljava/lang/Object;
             *
             * Probably ugly current code base brokens what would be a normal Java environemnt.
             * So I had to make it work using TransformerFactory.
             *
             * More information in: https://stackoverflow.com/questions/46183366/java-lang-nosuchmethoderror-asdom3serializerljava-lang-object-in-java-6
             *
            */

            TransformerFactory transformerFactory = TransformerFactory.newInstance(); 
            Transformer transformer = transformerFactory.newTransformer();
            DOMSource source = new DOMSource(document);
            StreamResult result =  new StreamResult(new StringWriter());
            transformer.transform(source, result);
            str = result.getWriter().toString();

            /* Make sure we write the ODT in "UTF-8". */
            out_after_removelines.write(str.getBytes("UTF-8"));

            /* Save "content.xml" within the XDocArchive. */
            out_after_removelines.close();
            XDocArchive.writeEntry(xdocarchive, "content.xml", out_after_removelines);
            return xdocarchive;
    }

In summary, after generating our report we changed the content.xml file that is within the ODT zip (by the way, an ODT file is just a zip with several files within), removing all paragraphs that have text @removeLine *only*, with the help of XML tools Java has.

Troubleshooting

error: type Pair does not take parameters

In my case I was compiling a project in 1.7 where I should use 1.6. Maybe the Pair type changed between these versions?

package com.sun.istack.internal does not exist

An error like that means that you are using a type that exists, but your are not allowed to access it, mostly because it is internal to the Java language. javac forbids it and the only way to override that is to use the -Dignore.symbol.table.

Using internal sun classes with javac

If you are using ant you may use the <compilerarg> tag to pass parameters to the compiler.

More information about ant

Ant: passing compilerarg into javac

*Important*: Other compilers, like the Eclipse Java Compiler don't have this restriction.

Eclipse Java Compiler

SEVERE [application] java.lang.NoSuchFieldError: ALIAS_TO_ENTITY_MAP

This error happens when you compile your class using a version of a package and run using another.

java.lang.NoSuchFieldError – How to solve SuchFieldError

The problem I had was that I was compiling it against one version of Hibernate and running it in JBoss with the version that comes with JBoss. The solution I found was to delete *hibernate* files from the lib directory of JBoss.

(Is there a non-destructive solution?)

The type <typename> cannot be resolved. It is indirectly referenced from required .class files

(2016-03-09)

If you look for this error on the web you'll get lots of information regarding the binary compability of JRE/JDK you are using. Make sure your target binary has version that match your Java version. Normally this is a parameter passed to the java compiler and is configured either in IDE settings or in an Ant_ file (build.xml) or build system file.

My problem, though, was different and simple. When compiling a huge problem, I forgot to add a jar file to the CLASSPATH. Since I was using an Ant_ build file (build.xml), it was enough to add the following line to the place that defined classpath::

    <pathelement location="location/of/the/jar/file" />

java.lang.NoClassDefFoundError: ...

(2018-06-15)

There are detailed explanation about this error on the web but basically it means your VM couldn't find a class at runtime (although it was found at compile time).

Why am I getting a NoClassDefFoundError in Java?

In my case, I was working at a big and legacy Java project whose structure is::

    external_libraries/
        libext1.jar
        libext2.jar
    the_project/
        internal_libraries/
            libint1.jar
            libint2.jar

When running an Ant script, an EAR file was created with libint1.jar and libint2.jar within. I was told to move some features out of the_project and create a library with for this features. First I tried to move out to external_libraries/libext3.jar and started to have these problems, because it was refering to classes in libint1.jar. The solution I found was to move it to internal_libraries/libint3.jar and NoClassDefFoundError worked. I don't know if it is a class loader configuration or something (I'm using JBoss at the moment), if you know, please, let me know.

It is worth to note that, to make it an internal library, I had add it to META-INF/application.xml and, of course, change build scripts to move it to the correct directory that will be used to create the EAR file.

Stricter JAR Visibility Rules

javax.transaction.HeuristicMixedException

(2022-12-07)

What in hell can cause this Exception? In a complex legacy Java EE application (using legacy Java 1.7 and legacy Jboss 5.1.0 GA) I was maintaining, I got this exception. More information from the enoumous stacktrace are:

09:41:07,387 ERROR [LogInterceptor] TransactionRolledbackException in method: public abstract java.lang.Object ...... throws ..... causedBy:
javax.transaction.HeuristicMixedException

This Java EE application uses PostgreSQL. Surprisingly, the solution for this error was to add option max_prepared_transactions = 20 (or any other value other than zero?) to postgresql.conf.

Error occurred during initialization of VM - java/lang/NoClassDefFoundError: java/lang/Object

When installing jdk-7u80-linux-x64.rpm, for some reason file rt.jar was not being unpacked, and running java without this lead to this error:

Error occurred during initialization of VM
java/lang/NoClassDefFoundError: java/lang/Object

After I made sure rt.jar was correctly unpacked, java just worked.

Reference: compilation - NoClassDefFoundError: java/lang/Object - Stack Overflow

More details: I was actually trying to install the RPM package into Ubuntu, using the alien utility that, for an unknown reason, was not installing all the contents of the RPM package.

alien-pkg-convert

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration$JdbcTransactionManagerConfiguration': Lookup method resolution failed

Got an error like this?

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration$JdbcTransactionManagerConfiguration': Lookup method resolution failed
...
Caused by: java.lang.IllegalStateException: Failed to introspect Class [org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration$JdbcTransactionManagerConfiguration] from ClassLoader [org.springframework.boot.loader.LaunchedURLClassLoader@6ea12c19]
...
Caused by: java.lang.NoClassDefFoundError: org/springframework/jdbc/support/JdbcTransactionManager
...

In my case, I had both spring-boot-starter-data-jpa and spring-jdbc as dependencies. spring-boot-starter-data-jpa already spring-jdbc as a dependency, but since I added a different version of spring-jdbc manually, classes and functions were different than what spring-boot-starter-data-jpa needed. So the solution I found was to remove spring-jdbc from pom.xml.