Resolving Multiple SLF4J Binding Warning

If you develop in Java long enough, you will eventually come across the Multiple Binding warning that looks something like the following:

SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:/C:/app/.m2/repository/ch/qos/logback/logback-classic/1.1.11/logback-classic-1.1.11.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/C:/app/.m2/repository/org/slf4j/slf4j-log4j12/1.7.24/slf4j-log4j12-1.7.24.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/C:/app/.m2/repository/org/apache/hive/hive-jdbc/1.1.0/hive-jdbc-1.1.0-standalone.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
SLF4J: Actual binding is of type [ch.qos.logback.classic.util.ContextSelectorStaticBinder]

In this specific case, the warning is stating that SLF4J was found in three different packages (logback-classic, slf4j and hive). Then it states which binding it actually picks up.

This is a warning that should have no consequences if left alone. As the SLF4J link mentioned in the warning notes:

The warning emitted by SLF4J is just that, a warning. Even when multiple bindings are present, SLF4J will pick one logging framework/implementation and bind with it. The way SLF4J picks a binding is determined by the JVM and for all practical purposes should be considered random. As of version 1.6.6, SLF4J will name the framework/implementation class it is actually bound to.

Embedded components such as libraries or frameworks should not declare a dependency on any SLF4J binding but only depend on slf4j-api. When a library declares a compile-time dependency on a SLF4J binding, it imposes that binding on the end-user, thus negating SLF4J’s purpose. When you come across an embedded component declaring a compile-time dependency on any SLF4J binding, please take the time to contact the authors of said component/library and kindly ask them to mend their ways.

However, if you are a perfectionist like me, you don’t like seeing this warning every time you run your program. It’s pretty easy to remove the warning. You go through the packages that have SLF4J bindings, and exclude it from the dependency.

For example, if the binding was found in Hive, you update from dependency declaration to:

<dependency>
  <groupId>org.apache.hive</groupId>
  <artifactId>hive-jdbc</artifactId>
  <version>1.1.0</version>
  <classifier>standalone</classifier>
  <exclusions>
   <exclusion>
    <artifactId>jetty-all</artifactId>
    <groupId>org.eclipse.jetty.aggregate</groupId>
   </exclusion>
   <exclusion>
     <groupId>org.slf4j</groupId>
     <artifactId>slf4j-log4j12</artifactId>
   </exclusion>
  <exclusion>
     <groupId>log4j</groupId>
     <artifactId>log4j</artifactId>
   </exclusion>
  </exclusions>

 </dependency>

Adding Rolling Logs capability to Spring Boot

Introduction

Spring Boot has LoggingSystem abstraction, which means you can use any Logging library you prefer.
Due to this constraint, Spring Boot only provides basic properties that can be written in your application.properties or application.yml files.

Spring Boot allows you to set the logging levels and location of log (file or console) from your configuration file. For example:

logging.level.org.springframework.web=DEBUG
logging.level.org.hibernate=ERROR
logging:
  file: log/application.log
  level:
    ROOT: INFO
    org.springframework.web.filter.CommonsRequestLoggingFilter: DEBUG
    com.fullstacktrace.logDemo: DEBUG

Rolling Logs

To configure more advanced or fine-grained settings for logging, you must provide it in native configuration format.
Spring Boot will pick up the native configuration from the default location. For logback that location is classpath: logback.xml . You can also overwrite this location by setting the logging.config property

logging:
  config: classpath:logback-local.xml

To set Rolling Logs, you need to provide the setttings in logback.xml file:

<configuration>
 <include resource="org/springframework/boot/logging/logback/defaults.xml"/>
 <springProperty scope="context" name="springAppName" source="spring.application.name"/>
 <!-- You can override this to have a custom pattern -->
 <property name="CONSOLE_LOG_PATTERN"
 value="%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}"/>

 <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
 <file>log/application.log</file>
 <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
 <!-- daily rollover -->
 <fileNamePattern>application.%d{yyyy-MM-dd}.log</fileNamePattern>

 <!-- keep 90 days' worth of history capped at 3GB total size -->
 <maxHistory>90</maxHistory>
 <totalSizeCap>3GB</totalSizeCap>

 </rollingPolicy>

 <encoder>
 <pattern>${CONSOLE_LOG_PATTERN}}</pattern>
 </encoder>
 </appender>
 <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
 <encoder>
 <pattern>${CONSOLE_LOG_PATTERN}</pattern>
 </encoder>
 </appender>
 <logger name="org.springframework.web.filter.CommonsRequestLoggingFilter">
 <appender-ref ref="FILE"/>
 </logger>
 <logger name="com.fullstacktrace.net">
 <appender-ref ref="FILE"/>
 </logger>
 <root level="INFO">
 <appender-ref ref="STDOUT"/>
 </root>

</configuration>

You can find more advanced logback setttings here

References

1. Spring Boot Docs
2. LogBack Docs

Using MongoDB with Spring Boot

Spring Boot is a powerful framework for building microservices. It comes ready to work with almost every type of database, including the newer NoSQL variety. This guide shows you how to quickly integrate MongoDB with your Spring Boot Application

Dependency

Spring Boot has hundreds of starter packages that allow you to avoid writing code. They have a starter for mongodb as well. Include the following dependency:

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

Configuration

Add your database connection string in the your configuration file:

spring.data.mongodb.uri= mongodb://localhost:27017/mongodb

Model

Setup your entity model, just like you would for a traditional SQL entity


@Entity
@Data
public class Permit {
    @Id
    public String id;
    public String permitNum;
    public String revisionNum;
    public String permitType;
    public String structureType;
    public String work;
    public String streetNum;
    public String streetName;
    public String streetType;
    public String streetDirection;
    public String postal;
}

Setup Repository


public interface PermitRepository extends MongoRepository {
    List findAll();
}

That’s it! you can start using your Model to GET or POST data from your MongoDB Database

Using H2 Database with Spring Boot

H2 is one of the more popular embedded databases out there today. Although there are 16-20 embedded databases out in the market, there are only 3 that work well with Spring (H2, Derby and HSQL).
Out of the three, H2 is considered the most matured and supported product. Although not recommended to use in production environment, H2 is robust enough to handle small scale production applications.

Using embedded H2 in Spring Boot is pretty simple. First you add the appropriate connection details in your configuration file, and then you can start using it in Spring like any other SQL database.

You need to add H2 as a maven dependency, there is no installs or setups required!

Dependency

<dependency>
     <groupId>com.h2database</groupId>
     <artifactId>h2</artifactId>
     <version>1.4.195</version>
</dependency>

Configuration

spring.datasource:
    driverClassName: org.h2.Driver
    url: jdbc:h2:mem:bootexample;MODE=MySQL

Data Model

Once you have your database setup, you can use it the same way you would use any other database in Spring. You create a model for your database entity

@Entity
@Table(name = "users")
public class User {
    @Id
    @GeneratedValue
    private Long id;
    @NotNull
    @NotEmpty
    private String firstName;
    @NotNull
    @NotEmpty
    private String lastName;
    @NotNull
    @NotEmpty
    private String password;
    @ValidEmail
    private String email;
    @NotNull
    @NotEmpty
    private String phoneNumber;
    private String lastOnline;
    private Boolean enabled;
    public String getLastOnline() {
        return lastOnline;

    }

    public void setLastOnline(String lastOnline) {
        this.lastOnline = lastOnline;
    }

    public Boolean getEnabled() {
        return enabled;
    }

    public void setEnabled(Boolean enabled) {
        this.enabled = enabled;
    }

    public String getEmail() {
        return email;
    }

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

    public String getPhoneNumber() {
        return phoneNumber;
    }

    public void setPhoneNumber(String phoneNumber) {
        this.phoneNumber = phoneNumber;
    }

    public Long getId() {
        return id;
    }


    public void setId(Long id) {
        this.id = id;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

Repository

Finally, you can use Spring’s JpaRepositoryto manipulate your data

package com.fullstacktrace.domain;

import com.fullstacktrace.domain.model.User;
import org.springframework.data.jpa.repository.JpaRepository;

public interface UserRepository extends JpaRepository<User, Integer> {
    public User findByEmail(String email);
}