Πέμπτη 19 Δεκεμβρίου 2024

REST vs SOAP vs Spring

 






  • @ResponseEntity automatically serializes Java objects to JSON
  • Spring uses the HttpMessageConverter to serialize the body of the ResponseEntity into the appropriate format (e.g., JSON, XML, plain text) based on the client's Accept header.

Παρασκευή 13 Δεκεμβρίου 2024

Interview questions for Java Backend #1

TreeSet - how does it sort incoming elements?


TreeSet accepts only objects, and sorts with their Comparable implementation


Case 1: Integer, Double, Long, etc

TreeSet uses their already existing Comparable implementation and sorts the numeric values automatically.


Case 2: Custom objects

We must implement our own Comparable for these custom objects. 




TreeSet - how does it use hashcode or equals?

No, it only uses compareTo() (or Comparator) to sort or locate an element.

HashSet uses hashcode() and equals()




TreeSet - what is a useful use case?

Hibernate gives us unordered result set.

We can feed it in a TreeSet to obtain an ordered/sorted set according to our business needs

E.g. treeSet.addAll(hibernateUnorderedSet)



TreeSet - how to traverse?

With advanced for loop or with iterator. Best use iterator - also removes items when iterating without ConcurrentModification.




Equals() - what's its purpose?

By default, Object.equals() checks equality by memory references

But in our business domain and collections, we may want to define equality with our own terms (override equals())

When we override equals, we must override hashcode, because of equals-hashcode contract:



Equals() - does HashSet use it?

HashSet and all Set collections (and Map ones) are hash-based.

That means they check for matching using hashcode() first. But in case of hashcode collision, they use equals() secondly.



Hibernate - what data structures to use per case?

Arraylist - For read-only collections, when random access is acceptable

LinkedList - For read-write collections, when modifications are frequent. LinkedList is fast for inserting/removing elements.

For example, use for Students of a Course entity, with @ElementCollection.



HashSet - When we want to filter query results with unique values


TreeSet - When we want to sort query results by our business comparison implementation.


Example for both:




TreeSet - how to have two comparison fields?

Sort answer: Using Comparator and overriding its compare()
Check: https://stackoverflow.com/questions/6850611/sort-a-list-of-objects-by-multiple-fields





Hibernate - when are entity beans loaded?



Hibernate session functions

session.get()
- Fetches immediately
session.load()
- Fetches when entity is queried (lazy)

- Note: Spring Data achieves this when Optional is used:


session.createQuery()
- Fetches immediately

session.refresh() / session.merge()
- After entity context is flushed, entities are again reloaded.


Lazy, Eager FetchType

E.g. Eager fetches child entities immediately, while Lazy only when accessed by parent.


Note: Spring Data uses Hibernate proxies for @Lazy and checked when data is actually asked, thus executing the query.


Second-level cache

We can ask Hibernate to first check in cache (e.g. Redis)



Cascade

Used on child entities, to indicate if parent events should propagate to children. Examples: - CascadeType.PERSIST
- CascadeType.REMOVE
- CascadeType.DETACH

This clearly affects entity beans loading.



COALESCE - explain?

Coalesce returns the first non-null value of a collection:


NVL- explain?
NVL provides a default value if the "salary" is null:



Query to troubleshoot a slow query?

Use EXPLAIN before your query



REST - is /person/1/delete ok?

No, DELETE person/1, is ok. The action (delete) shouldn't be included in http uri. It's already defined in our HTTP delete method.

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

JPA, Hibernate and Spring Data JPA

 

Why Use JPA ORMs?

Benefits of JPA ORMs

  1. 🟢 Simplifies Database Interaction 
    With JPA, developers can interact with the database using Java objects rather than writing SQL queries, making the code more maintainable and developer-friendly.

  2. 🟢 Reduced Boilerplate Code 
    JPA reduces repetitive SQL code, allowing developers to focus on business logic instead of low-level database details.

  3. 🟢 Strong Typing and Security 
    By integrating with Java, JPA enforces strong typing, minimizing runtime errors. Parameterized queries are handled internally, reducing the risk of SQL injection attacks.

  4. 🟢 Community Support 
    JPA is widely adopted and maintained, ensuring updates, bug fixes, and community-driven support.



When JPA ORMs Might Not Be Ideal
  1. 🔴Query Limitations
    Complex queries involving multiple joins, aggregations, or DB-specific operations may be challenging or inefficient with JPA.

  2. 🔴Overkill for Small Applications
    Small projects may not justify the learning curve and configuration overhead of JPA. JdbcTemplate is more preferable.

  3. 🔴Vendor Lock-In
    JPA abstracts database operations but can limit flexibility if specific DB features need to be utilized.

  4. 🔴Non-Optimized Queries
    Automatically generated queries may not always be performance-optimized, leading to potential inefficiencies.



Some key Hibernate Annotations and Features

    SessionFactory: 
- Immutable thread-safe cache of compiled mappings for a DB

    Session: 
- Single thread object, wraps JDBC conn, factory of Transaction

    Transaction: 
- Abtracts the app from JDBC, JTA transaction

    HQL: 
- Generates DB-independent queries using objects (entity names) instead of table names. Example:


    EntityManager: 
- Implements the JPA 2 specification.



  1. @GeneratedValue
    Specifies the generation strategy for primary key values:

    • AUTO: Uses the underlying database's strategy.
    • IDENTITY: Uses the database's auto-increment feature.
    • SEQUENCE: Leverages a database sequence.
    • TABLE: Maintains a separate table to store primary keys. Hibernate gets the Id keys from the DB, stores them in hibernate_sequence table and uses it to calculate next Id.
  2. @OneToMany
    Defines one-to-many relationships between entities.

    • Unidirectional: Only one entity is aware of the relationship.
    • Bidirectional: Both entities are aware of and can navigate the relationship.
    • Cascade options (PERSIST, MERGE, etc.) allow operations to propagate across related entities.
  1. @EmbeddedId / @Embeddable: Use for composite primary keys.

Cache Mechanisms

  1. First-Level Cache

    • Session-scoped, automatically enabled.
    • To bypass the cache for large reads, use JPQL or native SQL queries.

    Manually Clear Cache:

    session.detach(entity); // Detach a specific entity session.clear(); // Clear all entities
  2. Second-Level Cache

    • Application-scoped, supports cache providers like EhCache or Redis.
    • Ideal for large reads that don’t change frequently.





------------------------------- Using JPA Without Spring Data JPA ----------------------------


For projects not leveraging Spring Data JPA, the JPA's EntityManager API is the core tool for database operations.

EntityManager Highlights

  • Transactions: You must explicitly manage transactions, while with Spring Data JPA it happens behind the scenes
  • Query Language: Supports both JPQL (object-oriented) and native SQL.

Example Configuration (Hibernate + Spring Boot)

Include the spring-boot-starter-data-jpa dependency, then configure application.properties:






spring.datasource.url=jdbc:mysql://localhost:3306/my_database spring.datasource.username=root spring.datasource.password=secret spring.jpa.hibernate.ddl-auto=update spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect spring.jpa.show-sql=true



Service using EntityManager and @Transactional:










-------------------------- Spring Data JPA: Simplifying ORM Further -------------------------


Spring Data JPA abstracts away boilerplate repository code and simplifies transaction management.

Core Features

  1. Repositories
    Use predefined repository interfaces like CrudRepository, JpaRepository, and PagingAndSortingRepository to add functionality effortlessly:

    • CrudRepository: Basic CRUD operations.
    • JpaRepository: Adds advanced features like flushing persistence contexts and batch deletes.
    • PagingAndSortingRepository: Supports paging and sorting queries.
  2. Finder Methods
    Leverage naming conventions to create query methods, e.g.

    List<User> findTop3ByNameOrSurnameContainsOrderByName(String searchTerm);

Example Configuration (Spring Data JPA)

Configure repositories by extending one of the predefined interfaces:

@Repository public interface UserRepository extends JpaRepository<User, Long> { List<User> findByLastName(String lastName); }


How do Repositories work

Auto-implemented by Spring Data engine. At runtime, concrete class is created using proxies
and reflection. A proxy intercepts calls to @Repository class and then route mostly
to SimpleJpaRepository which has defined methods.

Logging with Spring Boot




LOGGING BASICS



             Logging frameworks:

  •                    SLF4J  - Specification / Abstraction that decouples business code from logging API
  •               Logback - Implementation of the above
  •               JUL - Same, another framework



             Logging levels:




If in our application we set logging level as INFO, then all below levels will also be activated:






... Meaning that log.debug won't print anything when app runs:



But log.info, log.warn, log.error instances will be printed in console.


 






LOGGING WITH SPRING BOOT


Spring Boot provides both SLF4J and Logback out-of-the-box:




To set logging level for our Spring app, in application properties: 



We can set different levels for various application or library packages:




Package org.hibernate will only print WARN and ERROR levels. We don't need to know every little detail. 

Same for JdbcTemplate.

If issues arise, we can DEBUG or TRACE these.



For advanced configuration,
logback-spring.xml:


  • Appender tag: We define a ConsoleAppender, meaning streamed logs will show on console.
  • Encoder-pattern tag: We can format the text with various configurations
  • Root tag: Finally we set our created Appender to root level




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)





Κυριακή 1 Δεκεμβρίου 2024

Microservices with Spring Cloud

MICROSERVICES WITH SPRING CLOUD





CONFIG - EUREKA - GATEWAY - BOOK-SERVICE





CONFIG SERVER


We centralize all application properties of business microservices, plus Eureka and Gateway


       Simple business service              

         book-service properties:




    Eureka / Discovery Server:
     All services register here. When service1 looks for service2, it looks up Eureka server           first.

     Eureka server properties:



   Gateway server:
    Provides one unified "gateway" / reverse proxy for our clients to make easy requests to        services, without complex configurations or CORS issues.
           
    Gateway server properties:




EUREKA 


 bootstrap.properties:





BOOK-SERVICE 


 bootstrap.properties:






GATEWAY


 bootstrap.properties:




Gateway uses Eureka (service discovery). 
This allows the gateway to dynamically resolve service instances.

Τρίτη 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);
};
}
}