Buzzworthy Java - Spring Boot & JHipster

Jeff Sheets - 2014

These slides are up on GitHub

jeffsheets.github.io/BuzzworthyJava

Also a printable version | Open Printable PDF

http://projects.spring.io/spring-boot/
http://jhipster.github.io/
https://twitter.com/java_hipster/status/522857424181809152

Happy Birthday

Github first commit

Buzzworthy Objectives

  • An introduction to both Spring Boot and JHipster
  • An overview of the technologies involved
  • Sample Code
  • Pragmatic Usage Ideas
  •  
  • Please ask questions! Open discussion
  • Everyone in this room is an expert!

About Me - Jeff Sheets

  • Java/Grails/Javascript for Object Partners
  •  @sheetsj
  • Website  sheetsj.com
  • jeffsheets@gmail.com
  • Omaha

Object Partners Inc (OPI)

  • Java, Groovy, JavaScript, Mobile, Open Source
  • ~100 Senior Consultants
    • Minneapolis, Omaha
    • Chicago, Denver
    • Average Tenure Over 5 years
  • Founded 1996

Set the record straight

  • We learned Java because it was the 'hipster' lang
  • C and COBOL were the old domain
  • Garbage Collection and Object Oriented FTW!

Web Apps?

  • We wrote Web apps before JSPs on Netscape
  • Instead of Apache mod_cgi and perl

Javascript?

  • We wrote Javascript (DHTML) before it was cool!
  • CSS when it wasn't LESS or SASS
  • AJAX before the blog post calling it AJAX

Where did it all go wrong?

http://www.buzzfeed.com/awesomer/the-most-hipster-things-that-have-ever-happened

Java's Image Problem

  • NodeJS, Ruby, Go, Swift, etc
  • Code Verbosity and Ceremony
  • Too "enterprisey"
  • App Servers

JVM Languages Help

  • Groovy and Scala and JRuby, etc...
  • Groovy was Swift before Swift
  • Kotlin (aka Scala the good parts)

Java's Speed Problem

  • Not app performance
    • Java wins that battle (see Netflix)
    • "Velocity on the JVM is the Killer App" - Andy Glover
  • But speed-to-market
    • Hard to jumpstart
    • XML everywhere
    • App Servers

Spicing up Java's Image

  • Spring Boot
    • Write an app in a tweet! (so hipster)
    • Opinionated Spring all wired up
    • Production-ready by default
    • No App Server Required - executable Jars
  • JHipster
    • Full stack AngularJS + Spring Boot
    • JS Build Tools
    • Beautiful Metrics
    • JHipster-loaded
  • Groovy Ecosystem
    • Groovy / Spock / Gradle / gvm / Grails
  • Others - Dropwizard, Akka, Vert.x
http://jhipster.github.io/

Spring Boot!  

  • Opinionated Spring all wired up
  • 100% Java Config (no XML!)
  • Executable Jars, embedded web server (or not)
  • Sane Profiles and Properties
  • Easy REST & Microservices
  • Spring Data JPA - dynamic finders (grails style)
  • Production-ready by default

Boot Install and CLI

  • gvm install springboot
  • A full tweet-sized 140 character app:
  • spring run GBR.groovy
  • @RestController
      class GBR {
          @RequestMapping("/")
          String gbr() {
              "Go Big Red! #Nebrasketball"
          }
      }
    

Jumpstart a Real Boot App

  • start.spring.io INITIALIZR
  • a la carte selection menu

Embedded Web Container

  • Just run as a main class in a jar
  • Great for cloud deploys. Microservices. Fat Jars.
  • Weblogic, Websphere, JBoss, etc NOT REQUIRED
  • gradle bootRun
  • java -jar appname.jar
  • Or run Main class from IDE

Or generate a War

  • gradle war
  • mvn package (also an executable jar file)
  • Warning Disclaimer:
    • Running latest of any Java stack on Websphere/Weblogic is tricky. Especially Hibernate/JPA.
    • Because classloaders...
    • It can be done
    • Get your Google / Stackoverflow keyword search game right

Java Config

  • No XML, all Java Config (unless you like XML)
  • @Configuration
      @EnableAutoConfiguration
      @ComponentScan
      public class Application {
      
          public static void main(String[] args) {
              SpringApplication.run(Application.class, args);
          }
          
      }
    

Everything is all wired up

  • No fiddling with hooking it all together
  • Production-ready out of the box

Profiles

  • Important piece of Spring Boot
  • dev/test/prod profiles
  • Available in core Spring too, but Boot leans on them

Properties

  • Hierarchical properties
  • application-*.properties, application.properties, System Props, JNDI Var, JVM Arg, ...

Boot-style Props in raw Spring

Cool to use application-*.properties in non-Boot apps too
public class PropertiesInitializer implements ApplicationContextInitializer {
public void initialize(ConfigurableApplicationContext applicationContext) {
    ConfigurableEnvironment env = applicationContext.getEnvironment();
    
    String[] activeProfiles = getActiveProfiles(env);
    
    for (String profileName : activeProfiles) {
        log.info("Loading properties for Spring Active Profile: {}", profileName);
        try {
            ResourcePropertySource propertySource = new ResourcePropertySource(profileName
             + "EnvProperties", "classpath:application-" + profileName + ".properties");
             
            env.getPropertySources().addLast(propertySource);
        } catch (IOException e) {
            log.error("ERROR during environment properties setup - TRYING TO LOAD: " + profileName, e);
            
            //Okay to silently fail here, as we might have profiles
            // that do not have properties files (like dev1, dev2, etc)
        }
    }
}

Database Props

Extend it further, to pull props from a database table
public class SpringPropertiesConfig {
@PostConstruct
public void initializeDatabasePropertySourceUsage() {
    MutablePropertySources propertySources = ((ConfigurableEnvironment) env).getPropertySources();
    
    try {
        //dataSource, Table Name, Key Column, Value Column
        DatabaseConfiguration databaseConfiguration = new DatabaseConfiguration(dataSource(), "AppConfiguration", "propertyKey", "propertyValue");
        
        //CommonsConfigurationFactoryBean comes from https://java.net/projects/springmodules/sources/svn/content/tags/release-0_8/projects/commons/src/java/org/springmodules/commons/configuration/CommonsConfigurationFactoryBean.java?rev=2110
        //Per https://jira.spring.io/browse/SPR-10213 I chose to just copy the raw source into our project
        CommonsConfigurationFactoryBean commonsConfigurationFactoryBean = new CommonsConfigurationFactoryBean(databaseConfiguration);
        
        Properties dbProps = (Properties) commonsConfigurationFactoryBean.getObject();
        PropertiesPropertySource dbPropertySource = new PropertiesPropertySource("dbPropertySource", dbProps);
        
        //By being First, Database Properties take precedence over all other properties that have the same key name
        //You could put this last, or just in front of the application.properties if you wanted to...
        propertySources.addFirst(dbPropertySource);
    } catch (Exception e) {
        log.error("Error during database properties setup", e);
        throw new RuntimeException(e);
    }
}

Spring Data JPA

  • Simple CRUD Repositories
  • (findAll, create, update, delete, and more)
  • Dynamic Finders
public interface AttendeeRepository extends JpaRepository {

    List findByOrderByNameDesc();
    
    List findByNameOrderByNameAsc(String name);
    
    List findByOrderByNameAsc();
}

Spring Data REST

  • Easy REST Entities
  • HATEOAS enabled
  • Better for quick prototypes than prod (customization)
@RepositoryRestResource(collectionResourceRel = "people", path = "people")
  public interface PersonRepository extends PagingAndSortingRepository {
  
    List findByLastName(@Param("name") String name);
    
  }

REST Exception Handling

  • Global handling based on Exception types
  • See RestResponseEntityExceptionHandler.java
@ControllerAdvice
  public class RestResponseEntityExceptionHandler extends ResponseEntityExceptionHandler {
      @ExceptionHandler({ Exception.class })
      @ResponseBody
      public ResponseEntity handleAnyException(Exception e) {
          return errorResponse(e, HttpStatus.INTERNAL_SERVER_ERROR);
      }
      
      @ExceptionHandler({ InvocationTargetException.class, IllegalArgumentException.class})
      @ResponseBody
      public ResponseEntity handleMiscFailures(Throwable t) {
          return errorResponse(t, HttpStatus.BAD_REQUEST);
      }
                

Spring MVC Tests  

class AccountControllerTest extends Specification {
  def accountController = new AccountController()
  
  MockMvc mockMvc = standaloneSetup(accountController).build()
  
  def "getAccount test hits the URL and parses JSON output"() {
      when: 'rest account url is hit'
      def response = mockMvc.perform(get('/rest/account')).andReturn().response
      def content = new JsonSlurper().parseText(response.contentAsString)
      
      then: 'securityService correctly returned account in JSON'
      response.status == OK.value()
      
      //Can test the whole content string that is returned
      response.contentAsString == '{"username":"spockUser"}'
      
      //Or can use the JsonSlurper version to test the JSON as object
      content.username == 'spockUser'
  }
}

Much more

  • JSP/GSP/Thymeleaf
  • Metrics - app-server style
  • No-SQL data stores, if that's your thing
  • Great docs
  • Simple tutorials

Old + New = Spring Boot

http://www.buzzfeed.com/awesomer/the-most-hipster-things-that-have-ever-happened

JHipster!  

  • Opinionated AngularJS + Spring Boot
  • Yeoman, Grunt, Bower, Gradle
  • Karma Client-side tests
  • Liquibase data bootstrapping
  • Thymeleaf, Hazelcast, Logback, HikariCP
  • Websockets with Atmosphere

Community & Branding

  • It starts with an image
  • Plus, the developers are amazing people
  • The project is fun and positive
  • Exhibit A: Response to Comic-Sans bug
  • Julien Dubois @juliendubois
  • Jérôme Mirc @JeromeMirc

Code Generation?

  • Yeoman generates a jumpstarted app
  • Also Grails-like entity generators
  • Personally, I use it to build up an app structure
  • At a minimum, generate an app and borrow ideas
  • Can 'update' from JHipster updates, but YMMV
  • vs Maven Archetypes

Slides!

  • So cool they provide their own slides
  • and they're much cooler than mine
  • so I borrowed the next few slides from them
  • Launch

JHipster Goals

  • A beautiful front-end
  • Latest HTML5/CSS3/JavaScript frameworks
  • Latest Java/Caching/Data access technologies
  • With security and performance in mind
  • And great developer tooling

High Level

Generate App

Steps
npm install -g yo
npm install -g generator-jhipster
yo jhipster
gradle bootRun
grunt server

Code Walk-thru

Entity Generators

Create a Meeting Attendee List
yo jhipster:entity location
//city, state, one-to-many attendee

yo jhipster:entity attendee
//name, previousAttendee, notes, many-to-one location

Show and Tell

  • Change db to on-disk
  • Display city, state on attendee.html list (Livereload!)
  • Improve previousAttendee Y/N

JHipster-loaded

  • Hot Swap almost any class
  • Stop bouncing your app server
  • Like JRebel but free! (as in speech AND beer)
  • Extension on Spring-loaded (used by Grails)

Dev and Prod profiles

  • Dev by default
  • Compile or run with -Pprod to use Prod mode
  • or an exectuable war:
mvn -Pprod package
java -jar jhipster-0.0.1-SNAPSHOT.war --spring.profiles.active=prod

Extras

  • Liquibase
  • Metrics screen
  • GZipping and HTTP Caching Headers
  • ehcache and hazelcast
  • Docker container
  • Heroku and Openshift deployments

Conclusion

All good? What's not to like?

  • Bloat - Downloads the whole internet
  • Memory footprint is tough for free cloud deploys
  • Treat container support as "beta" (my words)
    • I had trouble with Websphere 8.5.5

What about my legacy app?

  • Pull in pieces today
  • Look at github for Spring Boot
  • Generate a JHipster app and look around
  • Use Spring Profiles now!
  • Java Config!
  • Like building Grails from scratch...

Many Many Thanks!

  • Bootiful Apps talk by Josh Long
  • Exploring Microframeworks by Dan Woods
  • JHipster Twitter account @java_hipster

Questions  

https://twitter.com/Rokshimmer/status/514106534956388352