Εμφάνιση αναρτήσεων με ετικέτα Spring Boot. Εμφάνιση όλων των αναρτήσεων
Εμφάνιση αναρτήσεων με ετικέτα Spring Boot. Εμφάνιση όλων των αναρτήσεων

Δευτέρα 2 Δεκεμβρίου 2024

Exception handling with Spring Boot

 EXCEPTION HANDLING WITH SPRING BOOT



1. Use @ResponseStatus for simple cases




When ResourceNotFoundException get thrown, client will get a 404 status code.



2. Use @ControllerAdvice for Centralized Exception Handling



  • @ControllerAdvice handler intercepts exceptions thrown from any controller.
  • With ResponseEntity, we can return custom error messages, objects, HTTP status codes and response bodies.



3. ErrorResponse custom pojo class


     Moreover, we can define an ErrorResponse custom pojo model to include in                         ResponseEntity:






4. Include validation errors in ResponseEntity




    We can stream all errors gathered, into an ErrorResponse's errorMessage string value.




5. Map custom exceptions to error codes for API integrity




In our CustomBusinessException we link a specific Error Code (e.g. ERROR_1)
Then, we add it in ErrorResponse and to ResponseEntity.

That way, clients that consume our API will have a clear matching between our backend errors and an identifying reason (error code)





Τρίτη 22 Αυγούστου 2023

Overview - Run embedded Keycloak with Spring Boot

             Run embedded Keycloak with Spring Boot



No need to download and setup Keycloak locally. To run embedded Keycloak, we need generally to:

1.
Create a json for our Keycloak:





2.

Import maven dependencies and plugin in pom:


        <dependency>

            <groupId>org.jboss.resteasy</groupId>

           <artifactId>resteasy-jackson2-provider</artifactId>

            <version>${resteasy.version}</version>

        </dependency>


        <dependency>

            <groupId>org.keycloak</groupId>

            <artifactId>keycloak-dependencies-server-all</artifactId>

            <version>${keycloak.version}</version>

            <type>pom</type>

        </dependency>

        

        <dependency>

            <groupId>org.keycloak</groupId>

            <artifactId>keycloak-crypto-default</artifactId>

            <version>${keycloak.version}</version>

        </dependency>


        <dependency>

            <groupId>org.keycloak</groupId>

            <artifactId>keycloak-admin-ui</artifactId>

            <version>${keycloak.version}</version>

        </dependency>


        <dependency>

            <groupId>org.keycloak</groupId>

            <artifactId>keycloak-services</artifactId>

            <version>${keycloak.version}</version>

        </dependency>

    

         <dependency>

    <groupId>org.keycloak</groupId>

    <artifactId>keycloak-rest-admin-ui-ext</artifactId>

    <version>${keycloak.version}</version>

 </dependency>


...


  <plugin>

                <groupId>org.springframework.boot</groupId>

                <artifactId>spring-boot-maven-plugin</artifactId>

                <configuration>

                    <mainClass>com.codeinpackets.auth.

                         AuthorizationServerApp</mainClass>

                    <requiresUnpack>

                        <dependency>

                            <groupId>org.keycloak</groupId>

                            <artifactId>keycloak-model-jpa</artifactId>

                        </dependency>

                    </requiresUnpack>

                </configuration>

            </plugin>



3.
In our application yml, where we mention the json:


server:
  port: 8083

keycloak:
  server:
    contextPath: /auth
    adminUser:
      username: cip-admin
      password: pass
    realmImportFile: cip-realm.json



4.
Create a config properties class to bind our properties above:

@ConfigurationProperties(prefix = "keycloak.server")
public class KeycloakServerProperties {


    String contextPath = "/auth";
    String realmImportFile = "cip-realm.json";
    AdminUser adminUser = new AdminUser();


    // getters, setters
    public String getContextPath() {
        return contextPath;
    }
    public void setContextPath(String contextPath) {
        this.contextPath = contextPath;
    }
    public AdminUser getAdminUser() {
        return adminUser;
    }
    public void setAdminUser(AdminUser adminUser) {
        this.adminUser = adminUser;
    }
    public String getRealmImportFile() {
        return realmImportFile;
    }
    public void setRealmImportFile(String realmImportFile) {
        this.realmImportFile = realmImportFile;
    }
    public static class AdminUser {
        String username = "admin";
        String password = "admin";
        public String getUsername() {
            return username;
        }
        public void setUsername(String username) {
            this.username = username;
        }
        public String getPassword() {
            return password;
        }
        public void setPassword(String password) {
            this.password = password;
        }
    }
}



5.
Finally bind and run all together:

@SpringBootApplication
@EnableConfigurationProperties({ KeycloakServerProperties.class })
public class AuthorizationServerApp {


private static final Logger LOG = LoggerFactory.getLogger(AuthorizationServerApp.class);


public static void main(String[] args) throws Exception {
SpringApplication.run(AuthorizationServerApp.class, args);
}

// Log and verify Keycloak runs fine:
@Bean
ApplicationListener<ApplicationReadyEvent> onApplicationReadyEventListener(ServerProperties serverProperties,
KeycloakServerProperties keycloakServerProperties) {


return (evt) -> {
Integer port = serverProperties.getPort();
String keycloakContextPath = keycloakServerProperties.getContextPath();
LOG.info("Embedded Keycloak server has started, use http://localhost:{}{}", port, keycloakContextPath);
};
}
}

Δευτέρα 21 Αυγούστου 2023

@ConstructorBinding in Spring Boot

                  @ConstructorBinding in Spring Boot 3



This annotation is no longer needed along with @ConfigurationProperties classes. If there's at least one constructor, Spring Boot implicitly uses constructor binding for our properties.



@ConfigurationProperties(prefix = "mail.credentials")

public class ImmutableCredentials {


    private final String authMethod;

    private final String username;

    private final String password;


    public ImmutableCredentials(String authMethod, String username, String password) {

        this.authMethod = authMethod;

        this.username = username;

        this.password = password;

    }


    public String getAuthMethod() {

        return authMethod;

    }


    public String getUsername() {

        return username;

    }


    public String getPassword() {

        return password;

    }

}


Only if we have multiple constructors, we have to use it on the prefered constructor:


@ConfigurationProperties(prefix = "mail.credentials")

public class ImmutableCredentials {


    private final String authMethod;

    private final String username;

    private final String password;

 

// constructor 1

    @ConstructorBinding

    public ImmutableCredentials(String authMethod, String username, String password) {

        this.authMethod = authMethod;

        this.username = username;

        this.password = password;

    }


// constructor 2

    public ImmutableCredentials(String authMethod, String username) {

        this.authMethod = authMethod;

        this.username = username;  

    }


    public String getAuthMethod() {

        return authMethod;

    }


    public String getUsername() {

        return username;

    }


    public String getPassword() {

        return password;

    }

}




       @ConstructorBinding was introduced in Spring Boot 2.2


Before version 2.2 one could only use setters to bind properties with Java fields. But after 2.2, this annotation was introduced to allow binding the properties via a parameterized constructor.




Sources:

Spring docs - Constructor Binding

Spring docs - ConfigurationProperties

Spring Boot 3 - Constructor Binding





Τετάρτη 20 Οκτωβρίου 2021

Spring Certification: Spring Boot Basics

What is Spring Boot?
  • Extension of Spring Framework
  • Build fast production-ready applications, by:
  • providing auto-configurated dependencies
  • starter POMs (easy dependency management)
  • devTools (live code reload)
  • Fit for building apps in microservice architecture


What are the advantages of using Spring Boot?

  • Starter POMs: provide commonly used dependencies with correct versions and transitive dependencies
  • Embedded servlet containers (tomcat, jetty..), no need for WAR, packaging and deploying manually
  • Automatic Configuration: out of the box dependencies, but also configurable
  • Facilitates testing - provides default setup for unit IT tests
  • Solves boilerplate code in Spring projects (no XML)
  • Easily set  development and production profiles
  • Non-functional requirements: Security, Metrics, Externalized configuration and more


Why is it opinionated?
  • Convention over configuration principle is followed, meaning that framework tries to understand what to load, depending on what dependencies the developer has entered
  • Above approach can be edited


What things affect what Spring Boot sets up?
  1. Dependencies are set via starter POMs and/or additional by hand
  2. Spring Boot's autoconfigure module scans what there is on the classpath, and then employs Spring beans to integrate all dependencies (e.g. Spring MVC, Spring Data JPA, etc). This is done with use of @ConditionalOn.. inside AutoConfiguration classes.
  3. Furthermore, developer can set @ConditionalOn.. in his beans


    @ConditionalOn.. classes:

  • ConditionalOnBean - Spring Bean must exist
  • ConditionalOnMissingBean - Spring Bean must not exist
  • ConditionalOnClass - Class must exist
  • ConditionalOnMissingClass - Class must not exist
  • ConditionalOnExpression - spEL expression must result to true
  • ConditionalOnJava - Java JDK in certain version must exist
  • ConditionalOnJndi - JNDI location should exist
  • ConditionalOnProperty - property must exist
  • ConditionalOnResource - resource must exist


What is a Spring Boot starter? Why is it useful?

  • Spring Boot starters are sets of dependency descriptors that define all correct transitive dependencies and versions needed to provide a specific technology to include and use in applications. All official starters follow this pattern: spring-boot-starter-*
  • Developers can focus on business logic, not worrying much about dependency management.
  • Ensures no dependencies are missing and that all have versions that are compatible together.


Spring Boot supports both properties and YML files. Would you recognize and understand them if you saw them?
  • Spring provides option for externalization of configuration by Properties file or YML
  • YML is derived from JSON and is enabled when snakeYAML dependency is present
    • Recognizable from its hierarchical data structure


Can you control logging with Spring Boot? How?
  • Logging library:
    • If spring-boot-starter-web is used, by default Spring uses Commons Logging API, and Apache Logback as reference implementation. To change that, we need to exclude Logback in pom, and include another compatible e.g. Log4J
  • Logging levels:
    • In application properties use logging.level.root=<level> (application-wise).  Use debug=true to enable DEBUG mode globally
    • or com.app.package1=<level> (package-wise)
    • Alternatively, above can apply in a logback-spring.xml file
    • From VM options like: -Dlogging.level.org.springframework=DEBUG

  • Logging output: Use logging.file or logging.path in application properties


Where does Spring Boot look for application.properties file by default?
  1. In /config directory (outside of classpath/jar)
  2. In application directory (outside of classpath/jar)
  3. In /config directory of classpath (in jar)
  4. In classpath root directory (in jar)



How do you define profile specific property files?
  • application-{profile}.yml or application-{profile}.properties
  • If a property is not found in profile-specific file, it loads from the application.properties or application-default.properties (same for yml)



How do you access the properties defined in the property files?
  • In @Configuration class, annotate itself with @PropertySource("app.properties") and then annotate fields with @Value("app.some.property")
  • Alternatively, in Class1 add annotation @ConfigurationProperties(prefix = "app.some"), and then refer to field as "property". Finally, access property value in a second @Configuration class with @EnableConfigurationProperties(Class1.class)
  • @Autowire Spring's Environment, and access property with environment.getProperty("app.some.property")



What properties do you have to define in order to configure external MySQL?
  • spring.datasource.url=jdbc:mysql://<host>:<port>/<databaseName>
  • spring.datasource.username=<username>
  • spring.datasource.password=<password>
  • spring.datasource.driver-class-name=com.mysql.jdbc.Driver


How do you configure default schema and initial data?
  • Configure data.sql and schema.sql in /resources 
  • In properties: spring.datasource.initialization-mode=always
  • If using hibernate, spring.jpa.hibernate.ddl-auto=none
  • Spring loads according to platform set and loads data-{platform}.sql and schema-{platform}.sql. Platform is defined in property spring.datasource.platform=<vendor-platform>, e.g. mysql


What is a fat jar? How is it different from the original jar?
  • An executable jar containing all compiled classes and resources, along with dependencies as nested jars
  • project-1.2.3-SNAPSHOT.jar is the Fat jar, while inside it project-1.2.3-SNAPSHOT.jar.original is the original jar. 
  • To create a Fat jar, spring-boot-maven-plugin is needed to insert original jar in Fat jar. 
  • Fat jar is executable by default with java -jar project-1.2.3-SNAPSHOT.jar, while original is not.


What is the difference between an embedded container and a WAR?
  • Embedded container is used to run a single application's executable jar, and resides in jar itself as a dependency
    • To set up, use maven dependencies spring-boot-starter-web (provides embedded tomcat) and spring-boot-maven-plugin with repackaging goal (to integrate original jar in executable/fat jar)
  • WAR needs to be deployed in an Application Server, where many other war files (applications) can co-exist
    • To set up, use <packaging>war</packaging>, spring-boot-starter-web dependency and spring-boot-starter-tomcat with provided scope

What embedded containers does Spring Boot support?
  • Tomcat 
    • Default with spring-boot-starter-web
  • Jetty
    • First must exclude default Tomcat with <exclusion> tag
    • Set spring-boot-starter-jetty dependency
  • Undetow
    • Same setup logic as Jetty



















Τετάρτη 28 Απριλίου 2021

Spring Boot @DataJpaTest with simple @Repository stereotype and JdbcTemplate



Spring Boot @DataJpaTest with simple @Repository stereotype







1. DAO implementation with JdbcTemplate

@Repository public class UspNeighboursDAOImpl implements UspNeighboursDAO { @Autowired private JdbcTemplate jdbcTemplate; final String SELECT_QUERY = "select * from usp_neighbours where usp_id = ?"; @Override public List<Map<String, Object>> getNeighboursByUspId(int uspId) { return jdbcTemplate.queryForList(SELECT_QUERY, uspId); } } // DAO Interface public interface UspNeighboursDAO { List<Map<String, Object>> getNeighboursByUspId(int uspId); }


2. Testing

@DataJpaTest @AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) class ApplicationTests { @Autowired private UspNeighboursDAO uspNeighboursDAO; @Test public void testNeighbours1() { List<?> resList = uspNeighboursDAO.getNeighboursByUspId(2); assertEquals(resList.size(), 2); } }