Spring-Boot, Spring profiles and configuration files

Note to self: When using Spring-Boot, use application.conf as a base configuration for the needed values. Configuration values for the specific profile go into the application-<profile>.config file.

Profiles are activated by using either the -Dspring.profiles.active=<profile> VM flag or --spring.profiles.active=<profile> commandline arg.

Deploying a Spring-Boot application running with Java8 on OpenShift2

This post describes how to create and deploy a Spring-Boot application to RedHat OpenShift (version 2) when the application is using Java 8.

Edit 2015-10-04: In this newer post I show how to not install a custom JDK. So you should first read this post and then the linked one for additional information.

Normally deploying a Spring-Boot application on OpenShift is not too much pain and is explained in the Spring-Boot documentation. But some extra work is needed when the application is built and run with Java 8, as at the time of writing, the DIY cartridge of OpenShift only supports Java 7. And, to make things worse, the mvn command which is available in the DIY cartridge is rewritten by RedHat, so it will pick up Java 7 no matter what you set your JAVA_HOME to.

This post will show how to overcome these deficiencies by walking through the necessary steps to create a Spring-Boot based REST service which is deployed on OpenShift. To follow along you need

  • Java 8 installed
  • an OpenShift account
  • setup the rhc command line tool as described on OpenShift documentation
  • know how to create and set up an Spring Boot project (I use a maven project)

My sample is created on Mac OSX by using the terminal and IntelliJ. I will create a REST service named SayService which will just return it’s string input prepended by “you said: “. Not very interesting, but enough for this example.

Create the OpenShift application

As a first step I create the application on OpenShift. To do that, I change into the local directory where I want the app to be created and issue the following rhc command, assuming you are logged in to OpenShift with rhc:

rhc app-create sayservice diy

This creates the OpenShift application and clones it’s Git repository to your local sayservice directory. The structure is shown below:

sayservice
├── .git
├── .openshift
│   ├── README.md
│   ├── action_hooks
│   │   ├── README.md
│   │   ├── start
│   │   └── stop
│   ├── cron
│   │   ├── README.cron
│   │   ├── daily
│   │   │   └── .gitignore
│   │   ├── hourly
│   │   │   └── .gitignore
│   │   ├── minutely
│   │   │   └── .gitignore
│   │   ├── monthly
│   │   │   └── .gitignore
│   │   └── weekly
│   │       ├── README
│   │       ├── chrono.dat
│   │       ├── chronograph
│   │       ├── jobs.allow
│   │       └── jobs.deny
│   └── markers
│       └── README.md
├── README.md
├── diy
│   ├── index.html
│   └── testrubyserver.rb
└── misc
    └── .gitkeep

The diy subdirectory contains the sample, we ignore that. What we need to adjust later are scripts in the .openshift/action_hooks directory. And of course we need to add our source code for the service.

Create the Spring-Boot REST service

With the help of the Spring Boot Initializr (which I use from within IntelliJ, but the jar created on the Website is quite the same) I create a project that just has the Web/Web component added and where the Java version is set to 1.8. The important thing here is that the project is created in the sayservice directory so that the project files are added to the existing directory. After adding my standard .gitignore file, the directory contains the following data (not showing the contents of the .openshift directory again and skipping IntelliJ files):

sayservice
├── .git
├── .gitignore
├── .openshift
├── README.md
├── diy
├── misc
├── pom.xml
└── src
    ├── main
    │   ├── java
    │   │   └── com
    │   │       └── sothawo
    │   │           └── sayservice
    │   │               └── SayserviceApplication.java
    │   └── resources
    │       ├── application.properties
    │       ├── static
    │       └── templates
    └── test
        └── java
            └── com
                └── sothawo
                    └── sayservice
                        └── SayserviceApplicationTests.java

The following listing shows the pom.xml, notice the explicit setting of the java version to 1.8:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.sothawo</groupId>
  <artifactId>sayservice</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>jar</packaging>

  <name>sayservice</name>
  <description>Demo project for Spring Boot REST service on OpenShift</description>

  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.2.5.RELEASE</version>
    <relativePath/> <!-- lookup parent from repository -->
  </parent>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <java.version>1.8</java.version>
  </properties>

  <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
      <scope>test</scope>
    </dependency>
  </dependencies>
  
  <build>
    <plugins>
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
      </plugin>
    </plugins>
  </build>
</project>

Add the Service implementation

At the moment we have an application that has not yet a service defined, so we add the following Sayservice class:

/**
 * Copyright (c) 2015 sothawo
 *
 * http://www.sothawo.com
 */
package com.sothawo.sayservice;

import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

/**
 * Sample Service.
 *
 * @author P.J. Meisch (pj.meisch@sothawo.com).
 */
@RestController
@RequestMapping("/")
public class Sayservice {
    @RequestMapping(value = "/say/{in}", method = RequestMethod.GET)
    public String echo(@PathVariable(value = "in") final String in) {
        return "you said: " + in;
    }
}

After creating and running the application with

mvn package && java -jar target/*.jar

you can access and test it:

curl http://localhost:8080/say/hello
you said: hello

Create an OpenShift build script to install Java8 and build the application

The following script named build must be put in the .openshift/action_hooks directory (it must be executable):

#!/bin/bash

# define some variables for JDK 8
JDK_TGZ=jdk-8u60-linux-i586.tar.gz
JDK_URL=http://download.oracle.com/otn-pub/java/jdk/8u60-b27/$JDK_TGZ
JDK_DIR=jdk1.8.0_60
JDK_LINK=jdk1.8

# download JDK1.8 to the data directory if it does not yet exist, extract it and create a symlink
cd ${OPENSHIFT_DATA_DIR}

if [[ ! -d $JDK_DIR ]]
then
  wget --no-check-certificate --no-cookies --header "Cookie: oraclelicense=accept-securebackup-cookie" $JDK_URL
  tar -zxf $JDK_TGZ
  rm -fr $JDK_TGZ
  rm $JDK_LINK
  ln -s $JDK_DIR $JDK_LINK
fi

# export environment vriables
export JAVA_HOME="$OPENSHIFT_DATA_DIR/$JDK_LINK"
export PATH=$JAVA_HOME/bin:$PATH

# call our own mvn script with the right settings
cd $OPENSHIFT_REPO_DIR
./.openshift/mvn package -s .openshift/settings.xml -DskipTests=true

The script downloads the Oracle JDK if it is not yet available and extracts it to the OPENSHIFT_DATA_DIR directory.

The next thing to adjust is the mvn script. The one that’s available in the DIY cartridge resets JAVA_HOME, so I put the following mvn script in the .openshift directory:

#!/bin/sh
prog=$(basename $0)
export JAVACMD=$JAVA_HOME/bin/java
export M2_HOME=/usr/share/java/apache-maven-3.0.4
exec $M2_HOME/bin/$prog "$@"

As an alternative you might add a download of maven to the build script.

The last needed file for the build is the settings.xml, which I also put into the .openshift directory (Edit 2015-10-04: fixed variable with {} and added /.m2/repository):

<settings>
 <localRepository>${OPENSHIFT_DATA_DIR}/.m2/repository</localRepository>
</settings>

Set up start and stop scripts

Replace the files start and stop in the .openshift/action_hooks directory with the following ones (they must be executable):

start

#!/bin/bash
# The logic to start up your application should be put in this
# script. The application will work only if it binds to
# $OPENSHIFT_DIY_IP:8080

JDK_LINK=jdk1.8

export JAVA_HOME="$OPENSHIFT_DATA_DIR/$JDK_LINK"
export PATH=$JAVA_HOME/bin:$PATH

cd $OPENSHIFT_REPO_DIR
nohup java -jar target/*.jar --server.port=${OPENSHIFT_DIY_PORT} --server.address=${OPENSHIFT_DIY_IP} &

stop

#!/bin/bash
source $OPENSHIFT_CARTRIDGE_SDK_BASH

# The logic to stop your application should be put in this script.
PID=$(ps -ef | grep java.*\.jar | grep -v grep | awk '{ print $2 }')
if [ -z "$PID" ]
then
    client_result "Application is already stopped"
else
    kill $PID
fi

Deploy and run the application

After committing your files to git a final

git push

will upload all your changes to OpenShift, build and start the application. Check it out by calling

curl http://sayservice-yourdomain.rhcloud.com/say/it-works

and getting the answer

you said: it-works

So much for my first post concerning OpenShift.

Build a Spring-Boot REST service with Basic Authentication for several users

This post describes how to build a REST service with Spring-Boot that uses Basic-Authentication for several users and that uses the username of the authenticated user to do it’s work. Warning: A service using basic authentication should always use HTTPS as transport protocol, either by running behind a web server proxy or by setting up HTTPS by itself. I’ll cover the latter in a later post.

This might be a setup for a service, where for each user, data is stored in a database, so it not only is necessary to authenticate the user to use the service, but it is also necessary in the service to know which user is accessing the service.

The source code for this project can be found at GitHub. The coce relevant for this post is tagged post-20150728.

Setting up the project

I use IntelliJ IDEA (EAP Version 15 with Spring support) for the project and a maven project setup.

To create the initial project, I use Spring Initializr from within IDEA, but you can use https://start.spring.io as well to create the project. I named the project SecuRest, the initial dependencies are Core/Security and Web/Web:

Bildschirmfoto 2015-07-28 um 13.13.57

The created pom.xml looks like this:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.sothawo</groupId>
  <artifactId>securest</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>jar</packaging>

  <name>SecuRest</name>
  <description>Demo project for Spring Boot with Basic Authentication and HTTPS</description>

  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.2.5.RELEASE</version>
    <relativePath/> <!-- lookup parent from repository -->
  </parent>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <java.version>1.8</java.version>
  </properties>

  <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-security</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
      <scope>test</scope>
    </dependency>
  </dependencies>
  
  <build>
    <plugins>
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
      </plugin>
    </plugins>
  </build>
  

</project>

The Service

The first version of the implemented service just has one method which echoes it’s call arguments back:

/**
 * Copyright (c) 2015 sothawo
 *
 * http://www.sothawo.com
 */
package com.sothawo.securest;

import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

/**
 * Sample service.
 *
 * @author P.J. Meisch (pj.meisch@sothawo.com).
 */
@RestController
@RequestMapping("/service")
public class UserService {

    @RequestMapping(value = "/echo/{in}", method = RequestMethod.GET)
    public String echo(@PathVariable(value = "in") final String in) {
        return "You said: " + in;
    }
}

There is nothing yet to retrieve the name of the current user, we’ll do that later.

Running the application with the basic setup

This is all that is needed for the first basic application sceleton. When the application ist started, Spring-Boot sets up the security so that the whole application is secured and can only be accessed by a user user; the password is displayed on application startup in the log in a line like this (the password changes each time the application starts). This is the basic behaviour of Spring-Boot when spring-boot-starter-security is found on application startup.

Using default security password: e482e82e-1115-4fc4-86e4-bdcc432da039

When trying to access the application without passing in a username and password, the following result is returned:

curl localhost:8080/service/echo/hello
{"timestamp":1438088762118,"status":401,"error":"Unauthorized","message":"Full authentication is required to access this resource","path":"/service/echo/hello"}

With curl I can pass in the username and password like this:

curl user:e482e82e-1115-4fc4-86e4-bdcc432da039@localhost:8080/service/echo/hello
You said: hello

As an alternative I use IntelliJ’s REST Tool to create an authorization header for the user user and password e482e82e-1115-4fc4-86e4-bdcc432da039 and pass it along with the request:

curl -H "Authorization: Basic dXNlcjplNDgyZTgyZS0xMTE1LTRmYzQtODZlNC1iZGNjNDMyZGEwMzk=" localhost:8080/service/echo/hello
You said: hello

So now access to the service is granted. But, as I said, there is only one user named user allowed, and the password changes every time on application startup. Next, I’ll set up some users with passwords.

 

Setting up the Users

I am using the most basic form to setup different users, and that is by using an in-memory user store. To have that I add the following configuration class:

/**
 * Copyright (c) 2015 sothawo
 *
 * http://www.sothawo.com
 */
package com.sothawo.securest;

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

/**
 * Security configuration.
 *
 * @author P.J. Meisch (pj.meisch@sothawo.com).
 */
@Configuration
@EnableWebMvcSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
                .withUser("user1").password("secret1").roles("USER")
                .and()
                .withUser("user2").password("secret2").roles("USER");
    }
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests().anyRequest().fullyAuthenticated();
        http.httpBasic();
        http.csrf().disable();
    }
}

This configuration class configures two users with their passwords and roles. And although when starting the application, a password for the default user user is shown in the log, that user no longer can access the application, only the new configured two users can.

By using @EnableWebMvcSecurity and not @EnableWebSecurity the application has access to the current user in the following way:

/**
 * Sample service.
 *
 * @author P.J. Meisch (pj.meisch@sothawo.com).
 */
@RestController
@RequestMapping("/service")
public class UserService {

    @RequestMapping(value = "/echo/{in}", method = RequestMethod.GET)
    public String echo(@PathVariable(value = "in") final String in, @AuthenticationPrincipal final UserDetails user) {
        return "Hello " + user.getUsername() + ", you said: " + in;
    }
}

After restarting the application the service gives the following result:

curl user1:secret1@localhost:8080/service/echo/hello
Hello user1, you said: hello

So our service is protected by username and passwords and has access to the name of the current user.

Notice: As written at the beginning of this post, it is necessary to use HTTPS transport. This is covered in a later post.

Using Spring-Boot configuration properties in your own classes

When writing a Spring-Boot application it is possible to use your own custom configuration classes which are injected by spring into your application and which  are configured in the application.properties file. There is even support for autocomplete support in the properties file editor in IntelliJ IDEA (I suppose there is something similar in Eclipse or NetBeans, but I haven’t tried that). This post shows how to achieve this.

Basically this is used for auto configuration of Spring-Boot components, but can be used in the Spring-Boot application as well.

The configuration class

Let’s assume we have a class named Support which represents our configuration:

/**
 * Copyright (c) 2015 sothawo
 *
 * http://www.sothawo.com
 */
package com.sothawo.sbconfig;

import org.springframework.boot.context.properties.ConfigurationProperties;

/**
 * @author P.J. Meisch (pj.meisch@sothawo.com).
 */
@Component
@ConfigurationProperties(prefix = "support")
public class Support {

    private Integer productId;

    private Contact contact;


    public Contact getContact() {
        return contact;
    }

    public void setContact(Contact contact) {
        this.contact = contact;
    }

    public Integer getProductId() {
        return productId;
    }

    public void setProductId(Integer productId) {
        this.productId = productId;
    }

    @Override
    public String toString() {
        return "Support{" +
                "productId=" + productId +
                ", contact=" + contact +
                '}';
    }

    public static class Contact {

        private String name;

        private String email;

        public String getEmail() {
            return email;
        }

        public void setEmail(String email) {
            this.email = email;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        @Override
        public String toString() {
            return "Contact{" +
                    "name='" + name + '\'' +
                    ", email='" + email + '\'' +
                    '}';
        }
    }
}

This is a plain POJO; it contains an inner class, but that is only for the purpose of showing how Spring Boot configures a field that is itself a class. What marks this as a configuration class is the @ConfigurationProperties annotation, which by it’s prefix argument defines the prefix string to use in the properties file.

Edit 2015-09-21: added missing @Component annotation.

Enable the Spring Boot annotation processor

To have the annotation processed it is necessary to add the following dependency to the project’s pom.xml (notice that it’s optional):

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-configuration-processor</artifactId>
    <optional>true</optional>
</dependency>

After compiling the project there is a new file in the target/META-INF directory named spring-configuration-metadata.json. This is needed for autocomplete support, it contains the names, types and class information of the configuration class:

{
  "groups": [
    {
      "name": "support",
      "type": "com.sothawo.sbconfig.Support",
      "sourceType": "com.sothawo.sbconfig.Support"
    },
    {
      "name": "support.contact",
      "type": "com.sothawo.sbconfig.Support$Contact",
      "sourceType": "com.sothawo.sbconfig.Support",
      "sourceMethod": "getContact()"
    }
  ],
  "properties": [
    {
      "name": "support.contact.email",
      "type": "java.lang.String",
      "sourceType": "com.sothawo.sbconfig.Support$Contact"
    },
    {
      "name": "support.contact.name",
      "type": "java.lang.String",
      "sourceType": "com.sothawo.sbconfig.Support$Contact"
    },
    {
      "name": "support.product-id",
      "type": "java.lang.Integer",
      "sourceType": "com.sothawo.sbconfig.Support"
    }
  ]
}

Using the configuration object

The configuration object is used by injecting it in a Spring bean, for example like this:

/**
 * Copyright (c) 2015 sothawo
 *
 * http://www.sothawo.com
 */
package com.sothawo.sbconfig;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;

/**
 * @author P.J. Meisch (pj.meisch@sothawo.com).
 */
@Component
@EnableConfigurationProperties(Support.class)
public class SupportInfo {
    @Autowired(required = false)
    private Support support;

    @PostConstruct
    public void init() {
        if (null == support) {
            System.out.println("no support");
        } else {
            System.out.println(support.toString());
        }
    }
}

Configuring the object

IntelliJ supports editing the application.properties file with code completion:

sbcfg01

This shows the available configuration properties as well as their types and default values (if the fields of the configuration class are initialized with values). The screenshot shows how field names and inner classes are mapped to the corresponding property entries.

Custom theme for a Vaadin – Spring-boot application

Recently I wrote an application based on Vaadin Spring-boot, and when I needed to modify the theme of the application I needed to do some research as how to achieve that. I think that at the time the combination of Vaadin and Spring-boot is still pretty new so that information still must be sought. So in this post I describe the necessary steps.

I use the following versions of different tools:

  • Oracle JDK 1.8.0_45
  • vaadin 7.4.5
  • vaadin-spring-start 1.0.0.beta3
  • spring-boot 1.2.3.RELEASE
  • spring 4.1.6.RELEASE

My IDE is IntelliJ IDEA 14.1.3

Creating the basic application

I create the application project (named vsbt for vaadin spring boot theme) by using the Spring Initializr from within IDEA, but it can be done via the Website https://start.spring.io as well:

vsbt01

For this demo I set up a project with the following properties that has only Vaadin as a dependency:

vsbt02

vsbt03

After finishing the setup I have an IDEA maven project with the basic application class, but still with no UI:

vsbt04

So to have something visible, I add a MainUI class which uses the valo theme and which just inserts a button in the UI. The button is nonfunctional, as this demo is only concerning with theming the UI and not with functionality:

/**
 * Copyright (c) 2015 sothawo
 *
 * http://www.sothawo.com
 */
package org.sothawo.vsbt;

import com.vaadin.annotations.Theme;
import com.vaadin.server.VaadinRequest;
import com.vaadin.spring.annotation.SpringUI;
import com.vaadin.ui.Button;
import com.vaadin.ui.UI;
import com.vaadin.ui.VerticalLayout;

/**
 * @author P.J. Meisch (pj.meisch@sothawo.com).
 */
@Theme("valo")
@SpringUI
public class MainUI extends UI {
    @Override
    protected void init(VaadinRequest vaadinRequest) {
        VerticalLayout layout = new VerticalLayout();
        layout.setSizeFull();
        layout.setMargin(true);
        layout.setSpacing(true);

        layout.addComponent(new Button("This is a button"));

        setContent(layout);
    }
}

Compiling and running the application gives the following result in the browser:

vsbt05

Changing the theme

Now for changing the theme. I want to create a theme named colored where I change some colors. The first step ist to put the theme files (sass files) in the src/main/webapp/VAADIN/themes/colored folder:

vsbt06

 

The styles.scss file:

@import "addons.scss";
@import "colored.scss";

The colored.scss file:

@import "../valo/valo.scss";

@mixin colored {
  @include valo;

  .v-app {
    background-color: red;
  }

  .v-button {
    background-image: none;
    background-color: yellow;
  }
}

@include colored;

I don’t get into the details of sass files here. In the MainUI class the annotation for the theme must be changed to @Theme("colored").

When I now start the program after building the program with the following command:

mvn clean package
cd target
java -jar vsbt-0.0.1-SNAPSHOT.jar

then the browser shows no theme:

vsbt07

The reason for this is that the files that are located under the src/main/webapp directory are not considered when the jar is packaged, this is only done when building a war file. So the first step that needs to be done is to specify this directory as a resource directory in the maven pom.xml:

<build>
  <resources>
    <resource>
      <directory>src/main/resources</directory>
    </resource>
    <resource>
      <directory>src/main/webapp</directory>
    </resource>
  </resources>
  ...
</build>

One might be tempted to move the VAADIN/themes/colored folder to src/main/resources, but there is still a problem to be solved. When building and running the application, the logging output shows an error message like:

un 02, 2015 9:21:14 PM com.vaadin.server.VaadinServlet persistCacheEntry
WARNUNG: Error persisting scss cache /private/var/folders/xw/1zt9sly53_76h29g7067_y700000gp/T/tomcat-docbase.6378846904000133878.8080/VAADIN/themes/colored/styles.scss.cache
java.io.FileNotFoundException: /private/var/folders/xw/1zt9sly53_76h29g7067_y700000gp/T/tomcat-docbase.6378846904000133878.8080/VAADIN/themes/colored/styles.scss.cache (No such file or directory)
        at java.io.FileOutputStream.open0(Native Method)

This happens because the sass compiler – at least on my Mac – has problems with persisting the compiled css file. To remove that error it is necessary to add the sass compiler to the compile step in the maven pom.xml (and this is the reason to leave the files in the src/main/webapp directory, it’s there that the compiler searches for them):

<dependencies>
        <dependency>
            <groupId>com.vaadin</groupId>
            <artifactId>vaadin-themes</artifactId>
        </dependency>
</dependencies>
...
<plugins>
    <plugin>
        <groupId>com.vaadin</groupId>
        <artifactId>vaadin-maven-plugin</artifactId>
        <executions>
            <execution>
                <goals>
                    <goal>update-theme</goal>
                    <goal>compile-theme</goal>
                    <!--
                    <goal>clean</goal>
                    <goal>resources</goal>
                    <goal>update-widgetset</goal>
                    <goal>compile</goal>
                    -->
                </goals>
            </execution>
        </executions>
    </plugin>
</plugins>

When now compiling the project, the addons.scss and the colored.css files are created in the theme directory and packaged in the application, and after packaging and running, the browser shows the following application with no more logged errors:

vsbt08

I hope this post can help if somebody needs to theme a vaadin spring-boot application and has the same problems finding out where to put the files and how to compile them.