return 42;

by Jan Wedel

Modern Java Development is Fast

Java Development is fast - and fun. Believe it or not.

I hear a lot of Java bashing in Podcasts, mostly by developers that never did professional Java development and think about Java as the crappy Java browser plugin or ugly cross-platform desktop apps.

But that's not what I am talking about. What I mean is, you can nowadays write high quality production-ready code in Java in very little time. So here is an overview about the tools and frameworks I use every day.

This next section is a bit about my background and the issues I had with Java in the past. But feel free to skip it and jumpt to "A new Hope".

The XML Hell

A couple of years ago, I was almost done with Java. I did years of development with Java ME (Using Java 1.3 which is not fun at all) as well backend development in Java SE with Spring 2. Plus, there were some legacy system I had to maintain running struts for the front end.

<?xml version = "1.0" encoding = "UTF-8"?>

<beans xmlns = "http://www.springframework.org/schema/beans"
   xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation = "http://www.springframework.org/schema/beans
   http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

   <bean id = "helloWorld" class = "de.co.return.HelloWorld">
      <property name = "message" value = "Hello World!"/>
   </bean>
</beans>

A true beauty, isn't it?

I was basically sick of Spring 2 and Struts with its pile of XML that made refactoring a hell and was hard to read.

So I started the next backend project with plain Java SE. I did it completely test-driven. I was pretty fast, using IntelliJ to generate all the boilerplate code. I really took the DI "thing" very serious an over-engineered it. I had an interface for almost every class even if there was only one implementation. I did not use any mocking framework because I had some bad experience, too - with EasyMock and even PowerMock (do not use that!) and wrote all mocks by implementing the interface in a test if I needed it. I also had huge master boostrap class that actually created the production instances and did the actual injection. That was a 500loc monster.

MyConfiguration config = loadConfiguration();
FirstClass firstClass = new FirstClass(config);
SecondClass secondClass = new SecondClass(config, "someParam");
ThirdClass thirdClass = new ThirdClass(firstClass, secondClass);

(...)

OneHundredTwelfthClass oneHundredTwelfthClass = (...)

Thanks to very good test coverage, this application was working from the first moment on after putting it into production. The only place that I did not cover and that therefore had bugs was the SQL queries which, you guessed it, I wrote using plain JDBC.

All manually. And all because I had such a bad experience in the past using any kind of Framework.

I learned a lot but I didn't want to do that the rest of my life. So I was looking for some niche jobs like Erlang Backend Developer (I still love that language). I actually rejected a pretty good offer for a Java Dev position because they they told me in the interview that they were doing Spring. Finally, I was hired by a big company that was set on Java.

A New Hope

I was part of a new team that could chose the technologies we wanted to work with. We experimented with plain Java, Camel, Java EE, vert.x and then there was Spring 4 and Spring Boot and some other amenities that opened my eyes.

Spring - The Magic is Happening

Spring Core

With Spring core, I was obviously able to replace such an ugly bootstrap class with its @Autowire magic and, most importantly, without any XML necessary:

@Service
public class FooService {

    private final FooRepository repository;

    @Autowired
    public FooService(FooRepository repository) {
        this.repository = repository
    }
}

This is the core of Spring: Dependency Injection. It's practically the butler, that gets you all the stuff that you need on a silver plate. You just have to call for it. Spoiler: This gets even better with Lombok, see below.

I actually dropped my "interface for each class" pattern completely except for places where I needed more than one implementation.

Spring Web MVC - Gimme Some REST

I did not need any Webserver setup or configuration, I could easily write a @Controller that returns a Java class instance that gets serialized as JSON, no code necessary.

@Controller
@RequestMapping("/appointments")
public class AppointmentsController {

    private final AppointmentBook appointmentBook;

    @Autowired
    public AppointmentsController(AppointmentBook appointmentBook) {
        this.appointmentBook = appointmentBook;
    }

    @GetMapping
    public Map<String, Appointment> get() {
        return appointmentBook.getAppointmentsForToday();
    }

    @GetMapping("/{day}")
    public Map<String, Appointment> getForDay(@PathVariable @DateTimeFormat(iso=ISO.DATE) Date day, Model model) {
        return appointmentBook.getAppointmentsForDay(day);
    }

    @PostMapping
    public String add(@Valid Appointment appointment) {
        appointmentBook.addAppointment(appointment);
        return "redirect:/appointments";
    }
}

The code above publishes a new rest endpoint /appointments as well as two GET endpoints to retrieve all appointments and all appointments for a day as well as a POSTendpoint to create a new appointment. The class Appointment might actually be a persisted entity that gets automatically serialized as JSON. You'll get path variables properly decoded and fed into types method parameters. No additional code necessary.

See here for reference.

Spring Data

For very simple CRUD interfaces, I could use Spring Data repositories and even Spring Data REST to directly create a REST interface for my entities.

public interface OrderRepository extends CrudRepository<Order, Long> { }

For this repository, Spring Data REST exposes a collection resource at /orders. The path is derived from the uncapitalized, pluralized, simple class name of the domain class being managed. It also exposes an item resource for each of the items managed by the repository under the URI template /orders/{id}. *

*See here for reference.

Again, a lot of magic but but pretty cool though. While scanning the classpath for Spring managed classes, it finds the interface and creates an implementation for the repository on the fly, that you actually use to fetch entities from the data base (and all the CRUD operations as well) plus it will create a REST controller that will serve requests to that repository.

Spring Integration Tests

Using Mockito to mock objects in tests works like a a charm, AssertJ for test assertions and even all-set-up integration tests using @SpringBootTest with Real HTTP mock servers and in memory data bases running a complete application test without any external resources.

@RunWith(SpringRunner.class)
@SpringBootTest
public class MyTests {

    @MockBean
    private RemoteService remoteService;

    @Autowired
    private MyService service;

    @Autowired
    private MockRestServiceServer remoteServer;

    @Test
    public void exampleTest() {
        this.remoteServer.expect(requestTo("/greet/details"))
                .andRespond(withSuccess("hello", MediaType.TEXT_PLAIN));
        given(this.remoteService.someCall()).willReturn("world");

        String greeting = this.service.callRestService();

        assertThat(greeting).isEqualTo("hello world");
    }
}

As you see, there is a lot happing in this code. First, an actual Web Server called is started MockRestServiceServerthat will respond once /greet/details is requested. Then the service RemoteService of you application is mocked which is assumed to be called by the class under test MyService. When the method someCallis called, it will return "world". At the end, a verification using AssertJ is done.

Spring Security

The only downside was using Spring Security which does authentication and authorization. It comes with a variety of ready to use implementations as well as the option to write your own AuthenticationProvider. Unfortunately, IMHO it is designed badly (from the usability perspective) and even worse documented. Once you're starting to customize it the slightest bit, It never works as you would expect and you'll end up spending hours and days fixing it by trial and error. Simply put, Spring security sucks most of the time. I hope there is some overhaul done soon.

Spring Boot

Spring Boot makes it easy to create stand-alone, production-grade Spring based Applications that you can "just run". We take an opinionated view of the Spring platform and third-party libraries so you can get started with minimum fuss. Most Spring Boot applications need very little Spring configuration.

  • See here for reference.

Spring boot puts together all bits an pieces, applies a sensible default configuration and your good to go.

If you want a very funny and very good live coding example, I highly recommend Josh Long's video "Bootiful" Applications with Spring Boot. To quote the video:

Wow, such great!

JPA / Hibernate

When I once used Hibernate years ago, there was also that XML configuration hell I described earlier. But with recent JPA, you just do

@Entity
public class Customer {

  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  private Long id;

  private String firstname;
  private String lastname;

  // … methods omitted or replaced by Lombok
}

See here for reference.

and together with the Spring Data Repositories, you can access your entities easily. That means, that you're simply describing the data you are working with and you don't have to deal with how to get them.

The best thing is, you do not need to write any SQL. Hibernate is very good at creating optimized queries. It will pull the data from the database and maps it onto the @Entitiy class. If you you have some ugly names for tables or columns, you can simply annotate the fields. The above class expects a table CUSTOMER with columns ID, FISRTNAME and LASTNAME. You can customize everything you want if you need to access a legacy DB, e.g..

Flyway

Flyway is a tool to semi-automatically migrate data bases that integrates well with spring. Once the dependency is on the classpath, it will run a migration. It's semi automatic because it does not find out, what has actually changed in your model. You need to write actual SQL scripts that have versions. It will create a separate table to keep track what version you have in your data base and that execute the script automatically up to the point where the latest version is reached. There are other tools like Liquibase where you explain the changes in a meta language (XML, YAML, JSON) and liquibase actually transforms that in the SQL dialect that database needs.

JPA Testing

Doing integration test is very easy. It's actually as easy to include DB related tests. If you have an H2 test dependency in your project, the test runner will automatically create an in memory data base for you without the need to create a schema. You can just inject an EntityManager or even easier, a spring data repository:

@RunWith(SpringRunner.class)
@SpringBootTest
public class MyTests {

    @Autowired
    private MyService service;

    @Autowired
    private GreetingRepository repository;

    @Before
    public void cleanDb() {
        repository.deleteAll();
    }


    @Test
    public void worldTest() {
        repository.save(new Greeting("world"))

        String greeting = service.getGreeting();

        assertThat(greeting).isEqualTo("hello world");
    }

    @Test
    public void jpaTest() {
        repository.save(new Greeting("jpa"))

        String greeting = service.getGreeting();

        assertThat(greeting).isEqualTo("hello jpa");
    }

}

Lombok - No More Getters

When Java 8 came out, I was pretty impressed on how this old language was able to evolve. However, two things were missing from my point of view: Pattern Matching and a way to get rid of getters and setters.

We still do not have pattern matching (as e.g. in Erlang), but - and this is truly amazing - we can get rid of getters and setters by using a library. A lot of frameworks rely on the existence of getters and setter, Hibernate, Jackson and Spring itself.

When I first saw Lombok I thought this must be some code generation magic or - even worse - some runtime reflection trick. Plus, the website looked like it was from the 90ies. But when I checked it out, it turned out I was completely wrong. They are using a javac feature, compile-time annotations. So during compilation, Lombok's code is executed and generates additional byte code which generates no additional runtime overhead (compared to writing getters and setters manually) and no intermediate Java code.

Remember the FooServicefrom above. Using @AllArgsContructor, Lombok generates a constructor for all members.

@Service
@AllArgsConstructor
@Sl4j
public class FooService {

    private final FooRepository repository;
    private final MyProperties properties;

    public getUri(String path) {
        log.debug("Building uri from base Url {} and path {}", properties.getSomeUrl(), path)
        return properties.getSomeUrl() + path;
    }
}

Using @Sl4j, we get a free logger (instead of doing Logger.getLogger(...)) and there is more good stuff like generating @ToString and @EqualsAndHashcode.

With Spring 4.3, you can even drop @Autowire completely.

@Configuration
@ConfigurationProperties(prefix = "my.app")
@Getter 
@Setter
public class MyProperties {

    private String someUrl;
    private Integer someTimeout;
}

The above code can be used as spring properties to configure the application. You might argue that this snipped has more annotations than code and that's true. But I'd still prefer it over writing all the boiler-plate code myself.

It allows you to write a YAML file like the following an drop it next to the jar to change configuration:

my.app:
  some-url: http://foo.bar
  some-timeout: 5000

Yes, it will automatically allow you to use proper naming like some-timeout still know how to map that onto someTimeout. You'll get type safe configuration for you application for free. You can even add @Validated together with e.g. @Max(1000).

Maven

Maven is the library management tool. Ok, Maven is a lot of XML, ok but it just works like a charm. I've worked with Ant and it was so painful to get the same result.

I was looking forward to use Gradle in an Android project and oh my gosh, this is really bad. You'll need to write executable scripts that can do anything (and do do anything, especially in cases where you don't want it). You never know if its a method you're calling or if its configuration. A colleague and me ended up spending hours and days printf-debugging my build script until it did what I wanted.

[EDIT]

I've been criticised for "bashing" Gradle in the above paragraph. So here a little disclaimer. My experience is actually based on that one Android I've mentioned. So maybe it works better in a JavaSE project. But my criticism here ist basically: When there is some cool new tool, the first thing I expect is, that everything works just fine and you end up wondering how good it actually is. And maybe after some while you find out that some things actually could be improved in some way. That was my experience with Spring Boot and that was what was hoping for using Gradle. I just think, that if two an experienced developers do not get a build running and have a hard time finding out what is wrong, then it's just not as good as it could be from a UX perspective. Maybe it's more flexible but flexibility comes with a price... [/EDIT]

Just because of XML, Maven is well-defined and and you're almost not able to break stuff in a way that was not intented. Maven is library dependencies done right, especially when you compare it to other "package manager" that are loading code, build it (XCode, Erlang) or crap like NPM and Bower. Maven is just an integrated part of you build process, there is no need to download a library upfront like in pip (Python), you'll always get the exact version of that lib for that very project you're building.

Java

As mentioned above, Java 8 comes with some functional features and Lambdas are pretty handy although they aren't necessarily functional. Streams look great at first but most of the time you'll end up with spaghetti code that no one (not even you after one week) can read. Most often, you're better off with a good old for loop.

But generally, it try to write functional code (which was possible since the first version of Java) as much as possible. That means, a method should always return a value (not void) and it should always return the same value for the same parameters. This requires to

  • Not use system calls (like currentTimeMillis())
  • No interaction with files, DBs etc.
  • Use class variables

Obviously, if you do that a 100%, you're application is completely worthless because you have neither a way to control it nor to get any output. So what I try is to keep my core business logic as clean as possible and move the side-effects as far outside as possible. This benefits testing a lot.

IDE:

I actually transistioned through a lot of IDE in the past, starting from QBasic, Turbo Pascal, Visual Studio, Eclipse, NetBeans, XCode and even vim. But I lost my heart to IntelliJ IDEA which is just the single best IDE I've ever used. It starts with beeing beatiful and fast, supporting very good and intuitive keyboard short cuts, you can auto-type and auto-filter all menus, even context menus. It allows to use powerful refactorings and generating code for you. I supports very good debugging as well as showing code coverage in line.

You might be happy with your IDE right now, but you should have at least tried IDEA once and watch a video about the features.

Especially when I used XCode for an app project I did, I felt like in the stone age compared to IntelliJ. Unfortunately, even JetBrains AppCode still requires XCode for some things.

It's the Eco System

So, it's not about the language. Its not about the IDE or the build tool. It's every thing together that make Java development fun.


Jan Wedel's DEV Profile