Spring Boot: cannot find classfile ConfigurableApplicationContext (invalid LOC header)

Spring Boot with it’s maven starter dependencies is incredibly helpful to get a simple Spring Boot app up and running in no time, but occasionally you run into weird errors in Eclipse like:

The project was not built since its build path is incomplete. 
Cannot find the class file for 
org.springframework.context.ConfigurableApplicationContext. 
Fix the build path then try building this project

Or doing a mvn compile from your shell, something like:

[INFO] -------------------------------------------------------------
[ERROR] COMPILATION ERROR : 
[INFO] -------------------------------------------------------------
[ERROR] error reading /Users/kev/.m2/repository/org/apache/tomcat/embed/tomcat-embed-core/8.5.11/tomcat-embed-core-8.5.11.jar; invalid LOC header (bad signature)

Assuming you’re already using the Spring Boot Starter Web dependency:

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

.. errors about Classes not found or errors reading .jars (‘invalid LOC header’) could be related to jars in your local .m2 repo being corrupt.

This is pretty easy to correct if you go into your ~/.m2/repository/ and delete your downloaded dependencies. You can be more specific in what you delete if you have something that you can easily identify as coming from a specific dependency.

Adding dependent jars to your OpenShift Maven repo – take 2

Looking at my last post when I last did this, it’s been a year since I last deployed something to OpenShift with my own custom dependent jars 🙂 And looks like some of the paths might have changed since last time, but the approach is still the same.

What worked for me this time:

mvn install:install-file -DgeneratePom=true 
  -Dfile=../../jar-file-name-inc-version-number.jar 
  -DgroupId=your-group-id -DartifactId=artifact-name 
  -Dversion=0.0.1-SNAPSHOT -Dpackaging=jar

Looks like the relative path to where the jar gets copied to in your remote account changed slightly since last time.

The odd thing is I still ran into issues with my prebuild script file losing it’s executable flag, and it never seems to run as part of my build, but I can run it manually my ssh’ing into my account and just running it by hand.

Eclipse error: Access restriction: The type ‘xyz’ is not API

Eclipse has some pretty bizarre error messages that really don’t tell you exactly what the error is or how to fix it. This weekend I saw this one for example:

Access restriction: The type 'xyz' is not API (restriction on required library ...)

A quick Google told me what this actually means is that I have a line of code using a JDK API that is not in the currently selected runtime for the current project, but does exist in other available runtimes.

For example, when setting up a project with a Maven pom.xml, if you don’t explicitly specify what JVM version you want for the project, you get Java 5 by default.

There’s a couple of different ways to change the JVM version using Maven, but the approach I prefer is by adding properties (because it’s more concise than configuring the Maven compiler plugin):

<properties>
    <maven.compiler.target>1.8</maven.compiler.target>
    <maven.compiler.source>1.8</maven.compiler.source>
</properties>

Alternatively if you’re not using Maven, just change the JRE System Library in the project settings on the Java Build Path/Libraries tab (remove the one that’s currently there and add the version that does have the APIs that you’re using, most likely a later version).

Maven packaging notes

maven-dependency-plugin: Copy dependent jars into a /lib/ dir to be bundled with the package goal (note that you can’t have jars within jars and have them accessible on the classpath, so this just helps package the jars with your distribution):

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-dependency-plugin</artifactId>
    <version>2.6</version>
    <executions>
        <execution>
            <id>copy-dependencies</id>
            <phase>prepare-package</phase>
            <goals>
                <goal>copy-dependencies</goal>
            </goals>

            <configuration>
            <outputDirectory>target/classes/lib</outputDirectory>
            <overWriteIfNewer>true</overWriteIfNewer>
            </configuration>
        </execution>

        <execution>
            <phase>generate-sources</phase>
            <goals>
                <goal>sources</goal>
            </goals>
        </execution>
    </executions>
    <configuration>
        <verbose>true</verbose>
        <detail>true</detail>
        <outputDirectory>.</outputDirectory>
    </configuration>
</plugin>