- @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.
Clear and targeted goals and steps, simplistic structure, tested code packets from professional experience, focused on Java, Spring, Angular and more
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?
🟢 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.
🟢 Reduced Boilerplate Code
JPA reduces repetitive SQL code, allowing developers to focus on business logic instead of low-level database details.
🟢 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.
🟢 Community Support
JPA is widely adopted and maintained, ensuring updates, bug fixes, and community-driven support.
🔴Query Limitations
Complex queries involving multiple joins, aggregations, or DB-specific operations may be challenging or inefficient with JPA.
🔴Overkill for Small Applications
Small projects may not justify the learning curve and configuration overhead of JPA. JdbcTemplate is more preferable.
🔴Vendor Lock-In
JPA abstracts database operations but can limit flexibility if specific DB features need to be utilized.
🔴Non-Optimized Queries
Automatically generated queries may not always be performance-optimized, leading to potential inefficiencies.
@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.@OneToMany
Defines one-to-many relationships between entities.
PERSIST
, MERGE
, etc.) allow operations to propagate across related entities.@EmbeddedId
/ @Embeddable: Use for composite primary keys.
First-Level Cache
Manually Clear Cache:
session.detach(entity); // Detach a specific entity
session.clear(); // Clear all entities
Second-Level Cache
For projects not leveraging Spring Data JPA, the JPA's EntityManager API is the core tool for database operations.
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 abstracts away boilerplate repository code and simplifies transaction management.
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.Finder Methods
Leverage naming conventions to create query methods, e.g.
List<User> findTop3ByNameOrSurnameContainsOrderByName(String searchTerm);
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.
EXCEPTION HANDLING WITH SPRING BOOT
When ResourceNotFoundException get thrown, client will get a 404 status code.
2. Use @ControllerAdvice for Centralized Exception Handling
MICROSERVICES WITH SPRING CLOUD
CONFIG - EUREKA - GATEWAY - BOOK-SERVICE
CONFIG SERVER
We centralize all application properties of business microservices, plus Eureka and Gateway
Run embedded Keycloak with Spring Boot
<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>
server:
port: 8083
keycloak:
server:
contextPath: /auth
adminUser:
username: cip-admin
password: pass
realmImportFile: cip-realm.json
@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;
}
}
}
@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);
};
}
}