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.
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).
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.
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
.
*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).
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.
Ant: passing compilerarg into javac
*Important*: Other compilers, like the Eclipse Java Compiler don't have this restriction.
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.
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.
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
.