# Spring formation
## Authors
@Sophie @Benjamin @Simon
## Plan

## Intro
- Naissance octobre 2002
- Spring 6.0 en fin d’année 2022
- Patterns d’architecture prédéfinis
- Conteneur = cycle de vie, Conteneur IoC : léger, évolutif, maintenable, orienté aspect
- Pivotal développe tout
- Projet open source
- Sous licence Apache 2.
- IoC = Inversion of Control = Spring manage le cycle de vie des différent services (injection de dépendances)
---
## DI
- Principe : injecter un objet dans un autre
- Application Context représente le conteneur Spring, démarre les beans, leurs injections, leur gestions et destructions
- Avant: Configuration par XML
- Mtn: Annotations, On doit configurer le fait que l’on veut utiliser les annotations
### Setter injection
- Convention JavaBeen
- Plus clair que constructeur
- Dépendances optionnelles
### Constructor injection
- Recommandé
- Automatique sur dernière version de Spring (plus besoin d'annotation)
- Possibilité de rendre objets immutables grâce à "final"
- Facile les tests/mock
- Oblige à avoir dépendances correctement définies
### Field injection
- Spring injecte directement dans le champ grâce à la Java reflexion
- Magique
- Gênante pour tests unitaires
- Plus concise
### Notes
- Etre cohérent dans ses types d'injection.
- Meilleure portabilité de `@Inject` par rapport à `@Autowired` de Spring.
- Bean dispo ou pas: `Optional<Service>`
- On peut injecter dynamiquement:
`@Value("#toto.getValue()")`
---
## Profiles
:warning: Not Program arguments !
:arrow_right: Environment variables : `SPRING_PROFILES_ACTIVE=dev`
```java=
context.getEnvironment().setDefaultProfiles("prod");
```
```java=
@Profile("dev")
```
## AOP
- Joint point = Method Where you want to apply an aspect (poit.proceed)
- Point cut = Select several joint points (~regex), ex:
- Every methods which are called find...: `(execution(* ...*find*(..)))`
- `@Around("execution(* fr.ippon.training.spring.service.*.*(..))")`
- Advice = Method to add at the point cut
- Aspect = Point + Advice
### Types of aspects
- Before advice: before join point
- After returning: after joint point
- After throwing advice:
- After advice:
- Around advice (most powerful, wrap of method), ex:
```java
@Around("execution(* fr.ippon.training.spring.service.*.*(..))")
public Object watchTime(ProceedingJoinPoint point) throws Throwable {
Object res;
StopWatch stopWatch = new StopWatch();
stopWatch.start();
res = point.proceed();
stopWatch.stop();
log.info("{} temps d'exécution :{}ms", point.getSignature(), stopWatch.getTotalTimeMillis());
return res;
}
```
`@Aspect`
Annotate class configuration with
`@EnableAspectJAutoProxy`
## JDBC
`@EnableTransactionManagement`
- + basique qu'Hibernate
- Setup:
```java
@Configuration
@ComponentScan("fr.ippon.training.spring")
public class ApplicationConfiguration {
@Bean
public DataSource dataSource() {
return new EmbeddedDatabaseBuilder()
.setType(EmbeddedDatabaseType.H2)
.addScript("classpath:database_init.sql")
.build();
}
@Bean
public JdbcTemplate jdbcTemplate(DataSource dataSource) {
return new JdbcTemplate(dataSource);
}
}
```
Along with:
```sql=
create table Todo (todoId varchar(255) generated by default as identity, description varchar(255), priority integer not null, todoList_listId varchar(255), primary key (todoId))
create table TodoList (listId varchar(255) generated by default as identity, description varchar(255), primary key (listId))
create table User (email varchar(255) not null, password varchar(255), firstName varchar(255), lastName varchar(255), primary key (email))
create table User_TodoList (users_email varchar(255) not null, todoLists_listId varchar(255) not null, primary key (users_email, todoLists_listId))
alter table Todo add constraint FK_todoList_listId foreign key (todoList_listId) references TodoList
alter table User_TodoList add constraint FK_users_email foreign key (users_email) references User
alter table User_TodoList add constraint FK_todoLists_listId foreign key (todoLists_listId) references TodoList
insert into User (email, password, firstName, lastName) values ('philip@ippon.fr', 'Pa$$word1', 'Philip', 'Fry')
insert into User (email, password, firstName, lastName) values ('leela@ippon.fr', 'Pa$$word1', 'Leela', 'Turanga')
insert into User (email, password, firstName, lastName) values ('bender@ippon.fr', 'Pa$$word1', 'Bender', 'Rodríguez')
insert into User (email, password, firstName, lastName) values ('hubert@ippon.fr', 'Pa$$word1', 'Hubert', 'Farnsworth')
```
Use in the code:
:warning: Never use concatenation --> Prefer "**prepare statement**"
- secu pour les injections SQL
- perf
```java=
Collection<TodoList> todoLists = jdbcTemplate.query(
sql,
(rs, i) -> {
TodoList todoList = new TodoList();
todoList.setListId(rs.getString("listId"));
todoList.setDescription(rs.getString("description"));
return todoList;
},
listId
);
```
```java=
jdbcTemplate.update("insert into TodoList(listId, description) values (?, ?)",
todoList.getListId(), todoList.getDescription());
```
## Tests
mocks >> stubs (+ maintenable, + easier to setup)
### Mock
- Annotate test class with `@ExtendWith(MockitoExtension.class)`
- `@InjectMocks`: Entity in which you inject a mock dependency (declared as `@Mock`)
- To simulate the return of a mock object:
```java=
when(mockUserRepository.getUserByEmail("philip@ippon.fr")).thenReturn(testUser);
```
- To check how many times a method is called
```java
verify(mockUserRepository, times(3)).getUserByEmail("philip@ippon.fr");
verify(mockTodoListRepository).createTodoList(todoList);
verify(mockTodoListRepository).shareList(todoList, testUser);
```
```java
verifyNoMoreInteractions(mockUserRepository, mockTodoListRepository);
```
### Stub and field injection
When implementing a stub (example userRepositoryStub) which is to be inject by FIELD (example into userService), we must use reflexion
:arrow_right: userService depends on userRepositoryStub)
```java=
UserRepository userRepository = new UserRepositoryStub(); // Implement roughly the stub.
// TODO: Initialize userRepository stub with what you want.
UserService userService = new UserServiceImpl();
// Inject stub using java reflexion.
ReflectionTestUtils.setField(userService, "userRepository", userRepository);
```
### Integration Test
Annotate test class with
```java=
@ExtendWith(SpringExtension.class) // Contexte Spring, allows DI !
@ContextConfiguration(classes = { ApplicationConfiguration.class })
```
Annotate a test method with `@Transactional` to make it independent between them. (allows to clean the data between 2 tests so that the tests are coherent)
```java=
@Test
@Transactional
```
### ORM
- ORM tools like Hibernate implements JPA specifications (Java Persistence API).
- Allows to focus on the java objects, and business logic.
Two main ORMs:
- Hibernate (widely used, recommends using the JPA)
- EclipseLink
**NB**: Search for Spring Data JPA ! (layer on Hibernate) (2012) https://spring.io/projects/spring-data-jpa
#### Hibernate


**NB**: En fait Hibernate = Room mais pour Android... :see_no_evil:
Doc: https://javabydeveloper.com/jpa-entity-lifecycle-jpa-developer-should-know/
Autres API:
- JPQL (Java Persistence Query Language) custom request
- API Criteria: + complexe, pour des recherches par filtre
**NB**: Quarkus --> notion de `ActiveRecord` = une entité peut contenir des *opérations* --> vient de Ruby on Rails
Template: permet de faciliter l'utilisation d'Hibernate
To make queries into a class,
- Add a bean entityManager in the class configuration
- Add the property`@PersistenceContext private EntityManager em;` into the classes you want to use.
Methods:
- Get `em.find(TodoList.class, listId);`
- Create `em.persist(todoList);`
- Custom query
```java
return em.createQuery(
"select t from Todo as t join t.todoList tl join tl.users u where u.email = :email",
Todo.class)
.setParameter("email", email)
.getResultList();
```
:warning: Using @Data for JPA entities is not recommended. It can cause severe performance and memory consumption issues
## Validators
- Size of a String `@Size(min = 1, max = 255)`
- `@Empty` / `@NotEmpty`
- `@AssertTrue` / `@AssertFalse`
- `@Null` / `@NotNull`
- `@Max` / `@Min`
- `@Future` / `@Past`
- `@Digits(integer=6, fraction=2)`
- `@Pattern(regexp="\\(\\d{3}\\)\\d{3}-\\d{4}")`
- ...we can create custom validators
## Spring MVC
Spring Web MVC is the original web framework built on the Servlet API and has been included in the Spring Framework from the very beginning.
Spring MVC, as many other web frameworks, is designed around the front controller pattern where a central Servlet, the DispatcherServlet, provides a shared algorithm for request processing, while actual work is performed by configurable delegate components. This model is flexible and supports diverse workflows.
### Spring MVC Configuration
- Add a web package for your routes and other
- :warning: Do not scan the beans defined in this package
- Implement the `WebApplicationInitializer` interface
- Override `onStartup(ServletContext servletContext)`:
- Add a configured listener
- `servletContext.addListener(new ContextLoaderListener(rootContext))`
- `dispatcherContext.register(WebConfiguration.class);`
- Add a Servlet DispatcherServlet
- `ServletRegistration.Dynamic servletConfig = servletContext.addServlet("dispatcher", new DispatcherServlet(dispatcherContext));`
- `servletConfig.addMapping("/*");
- Add filter to handler ETags
- `FilterRegistration.Dynamic etagHeaderFilter = servletContext.addFilter("etagFilter",
new ShallowEtagHeaderFilter());`
- Add `@EnableWebMvc` in configuration class
### Route configuration
To return JSON text :
```java=
@GetMapping(produces = MediaType.APPLICATION_JSON_VALUE)
```
curl | jq
## Spring Security
- Secures REST method calls
- Class/File configuration --> XML outdated... again
:warning:
- **Authentification** = person identity (companies uses LDAP servers)
- **Autorization** = correct rights
Spring handles both of these concepts
Is a user connected? Does he/she have the rights?
What error pages?
Retrieve person identity:
- Spring LDAP
- or database (retrieve username then username's roles)
### Config class setup
#### HTTP security
In the WebConfigurer (startup), add a servlet filter
```java=
FilterRegistration.Dynamic delegatingFilterProxy = servletContext.addFilter("springSecurityFilterChain",
new DelegatingFilterProxy());
delegatingFilterProxy.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST,
DispatcherType.FORWARD, DispatcherType.ASYNC), true, "/*");
```
- Must implement `WebSecurityConfigurerAdapter`
- Annotated with `@EnableWebSecurity`
- Override `configure(HttpSecurity http)` method to add http filters (add the filters to http in a functional way)
- Override `configure(AuthenticationManagerBuilder auth)` method to add a jdbc manager (authentification)
- setup datasource
- how to query username
- the authorities of a username
NB: Don't scan the config package in the main config class. Instead, force the import of the security class config into it. `@Import(SecurityConfiguration.class)`
NB: {noop}: no encodage
#### Java methods security
- To enable handling of security annotations `@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)`
### Security Tests
`@WithUserDetails("toto@tata.fr")`
`@MockUser`
## Spring Boot
### Les starters
| Starters | Description |
| -------------------------------- | ------------------------------------------------- |
| **spring-boot-starter-web** | Développer une application web |
| **spring-boot-starter-data-jpa** | Accéder à la base de données via JPA/Spring Data |
| **spring-boot-starter-security** | Sécuriser l'application via spring security |
| **spring-boot-starter-test** | Tester votre application avec Spring |
--> Actuator
Plus 1 plugin
### Conditional
`@Conditional` -> ...
`@Conditional(ConditionalProfile.class)`
Classe d'autoconfiguration `AutoConfigurationBlabla`
Conf per environement
### Tests
```java=
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK)
@AutoConfigureMockMvc
```
## Spring Data
--> Beaucoup de connecteurs pour les bdd noSQL
Plus besoin d'implémenter le Repository !!
`extends JpaRepository<TodoList, String>`
++ `@Enable....` on Configuration class
## Spring WebFlux
Parallel to Spring Web MVC, Spring Framework 5.0 introduced a reactive-stack web framework whose name, “Spring WebFlux,”.