Saturday, November 10, 2018

Looking for OpenJDK for Windows?

If you're looking for a Windows build of OpenJDK, you will be happy to know that several organizations provide pre-built versions of OpenJDK for Windows:
  • Azul - https://www.azul.com/downloads/zulu/zulu-windows/
  • Red Hat - https://developers.redhat.com/products/openjdk/overview/
As always, you should read the terms and conditions to see if these binary distributions are right for your use case.

Or, you could build it yourself.

Saturday, November 3, 2018

Upgrading Java - TL;DR : Stick with OpenJDK LTS versions

With the new, faster release cycle of Java there is a lot of confusion about when to upgrade.   Upgrading Java is non-trivial for a large system, so it needs to be thought through carefully - you have to think about the IDE, all your tools, and all the dependencies.

This awesome blog post covers a lot of the details.

Here's another awesome post about upgrading to Java 11

However, if you are using the Spring Framework, this decision is made simpler: Spring is only officially supporting LTS releases.   I think this makes a lot of sense.  For example: Spring Boot 2.1 Released - Java 11 Support

In my day job, the Spring Boot apps lean heavily on Spring's dependencies, so that we can leverage all the testing done by the Spring community.   Yes, that means working with something that's not the absolute bleeding edge, but using bleeding edge stuff is not the goal for us.  The goal is to produce applications that delight our users and add value to the business.

Sunday, October 28, 2018

Slimming down a Spring Boot app for testing

One of my favorite things about Spring Boot is the ability to launch an application in embedded mode and do some pseudo-integration-testing (that is, it's integration testing because I'm able to call the embedded app over the loopback network, as if the test were running on a different machine).   Of course you can launch your 'real' application that lives in your 'main' source folder, and you can enable / disable parts of the application with Spring profiles.

But what if you want to create a specialized Spring Boot app, just for testing?   Well, you can!

For example, in src/test/org/example/test/app/TestServer.kt we can make an app class (btw, this is Kotlin, just so you know):

package org.example.test.app

...imports blah...

@SpringBootApplication()
@Import(SomeConfig::class)
class TestGraphQLClientApp {
    /**
     * Defines the main resolvers: Query and Mutation.
     */
    @Bean
    fun resolvers(query: GraphQLQueryResolver) = listOf(query)

}

  • This is a GraphQL server, and I'm going to test a simple GraphQL client with it.   There are more components behind the scenes.
  • I'm putting it in the app sub-package to avoid loading any component in the main app or anywhere else unintentionally.    Remember that a Spring Boot app class implies a 'component scan' of the package it lives in, and all sub-packages!
  • SomeConfig is imported, and this brings in whatever components from the main code or elsewhere.
  • Specialized test components can be defined in packages or sub-packages.
We can make a test like this:

package org.example.test

... imports blah ...

@RunWith(SpringJUnit4ClassRunner::class)
@SpringBootTest(classes = [TestGraphQLClientApp::class, HttpClientConfiguration::class],
        webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class GraphQLClientTest {
    companion object : KLogging()

    @LocalServerPort
    private val port: Int = 0

    @Autowired
    private lateinit var factory: RestTemplateFactory

    // These have to be 'by lazy' because Spring will inject the fields they rely on after init.

    private val template by lazy { factory.createRestTemplate() }

    private val baseUrl by lazy { "http://localhost:$port/graphql" }

    private val client by lazy { GraphQLClient(baseUrl, template) }

    @Test
    fun basicClientTest() {
        client.query("query { foo }").also { value ->
            logger.info { prettyPrint(value) }
            assertEquals("foo", assertHasField(value, "data", "foo").asText())
        }
        client.query("query { getThing(id: \"12345-ABC\") { one two } }").also {
            logger.info { prettyPrint(it) }
        }
    }
}
  • Note that the default 'properties' will be loaded from application.properties or application.yml.  If we want to override this, we should probably make a profile and use it from the test.
So what's the problem?   The problem is that, in this particular context I have JPA and a few other Spring Boot 'starter' dependencies.   So, when the test class starts the Spring Boot app, it launches:
  1. A JDBC Data Source
  2. Liquibase (my preferred data migration tool)
  3. JPA and Hibernate
Those are all great tools, and it's super convenient to have all these 'auto starters' but they are not needed in this particular test.   How to turn them off and "slim" down my application?   There are two approaches:
  1. Create a profile, and disable some things in that profile - This works for the autostart modules that support it, but not all of them do.
  2. Use 'exclude' in SpringBootApplication to disable the autostart modules.
Using exclude is easy, and since it prevents Spring from loading the autostart modules in the first place, it can reduce startup time.   So for a simple web app, we can disable all the database modules:

@SpringBootApplication(exclude = [
    LiquibaseAutoConfiguration::class,
    DataSourceAutoConfiguration::class,
    DataSourceTransactionManagerAutoConfiguration::class,
    HibernateJpaAutoConfiguration::class])

That's all we need to do!   Now the test app starts up in about 9 seconds.

See also: