Skip to content
This repository has been archived by the owner on May 3, 2023. It is now read-only.

Commit

Permalink
Refactor/immutability (#46)
Browse files Browse the repository at this point in the history
refactor: using immutability wherever it's possible
  • Loading branch information
annibalsilva authored Dec 1, 2022
1 parent ba09450 commit c25a663
Show file tree
Hide file tree
Showing 23 changed files with 101 additions and 535 deletions.
2 changes: 1 addition & 1 deletion .github/badges/branches.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion .github/badges/jacoco.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package ca.bc.gov.backendstartapi.config;

import ca.bc.gov.backendstartapi.util.ObjectUtil;
import java.util.Arrays;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
Expand All @@ -23,7 +22,7 @@ public class CorsConfig implements WebMvcConfigurer {
*/
@Override
public void addCorsMappings(CorsRegistry registry) {
if (!ObjectUtil.isEmptyOrNull(allowedOrigins)) {
if (allowedOrigins.length != 0) {
log.info("allowedOrigins: {}", Arrays.asList(allowedOrigins));

registry
Expand Down
42 changes: 21 additions & 21 deletions src/main/java/ca/bc/gov/backendstartapi/config/SecurityConfig.java
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
package ca.bc.gov.backendstartapi.config;

import ca.bc.gov.backendstartapi.util.ObjectUtil;
import com.nimbusds.jose.shaded.json.JSONArray;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
Expand Down Expand Up @@ -64,27 +63,28 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {

private Converter<Jwt, AbstractAuthenticationToken> converter() {
JwtAuthenticationConverter converter = new JwtAuthenticationConverter();
converter.setJwtGrantedAuthoritiesConverter(roleConverter());
converter.setJwtGrantedAuthoritiesConverter(roleConverter);
return converter;
}

private Converter<Jwt, Collection<GrantedAuthority>> roleConverter() {
return jwt -> {
final JSONArray realmAccess = (JSONArray) jwt.getClaims().get("client_roles");
List<GrantedAuthority> authorities = new ArrayList<>();
if (ObjectUtil.isEmptyOrNull(realmAccess)) {
String sub = String.valueOf(jwt.getClaims().get("sub"));
if (sub.startsWith("service-account-nr-fsa")) {
authorities.add(new SimpleGrantedAuthority("ROLE_user_read"));
authorities.add(new SimpleGrantedAuthority("ROLE_user_write"));
/**
* Parse the roles of a client from the JWT, if they're present; if not, subjects with service
* accounts are granted read and write permissions.
*/
private final Converter<Jwt, Collection<GrantedAuthority>> roleConverter =
jwt -> {
if (!jwt.getClaims().containsKey("client_roles")) {
String sub = String.valueOf(jwt.getClaims().get("sub"));
return (sub.startsWith("service-account-nr-fsa"))
? List.of(
new SimpleGrantedAuthority("ROLE_user_read"),
new SimpleGrantedAuthority("ROLE_user_write"))
: List.of();
}
return authorities;
}
realmAccess.stream()
.map(roleName -> "ROLE_" + roleName)
.map(SimpleGrantedAuthority::new)
.forEach(authorities::add);
return authorities;
};
}
final JSONArray realmAccess = (JSONArray) jwt.getClaims().get("client_roles");
return realmAccess.stream()
.map(roleName -> "ROLE_" + roleName)
.map(SimpleGrantedAuthority::new)
.collect(Collectors.toUnmodifiableList());
};
}
71 changes: 0 additions & 71 deletions src/main/java/ca/bc/gov/backendstartapi/dto/ExampleDto.java

This file was deleted.

54 changes: 4 additions & 50 deletions src/main/java/ca/bc/gov/backendstartapi/dto/UserDto.java
Original file line number Diff line number Diff line change
@@ -1,57 +1,11 @@
package ca.bc.gov.backendstartapi.dto;

import ca.bc.gov.backendstartapi.response.BaseResponse;
import ca.bc.gov.backendstartapi.util.Empty;
import ca.bc.gov.backendstartapi.util.ObjectUtil;
import java.util.Objects;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

/** This class represents a User data transition object. */
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class UserDto implements BaseResponse, Empty {

@Size(min = 2, max = 20)
@NotBlank
private String firstName;

@Size(min = 2, max = 20)
@NotBlank
private String lastName;

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
UserDto userDto = (UserDto) o;
return firstName.equals(userDto.firstName) && lastName.equals(userDto.lastName);
}

@Override
public int hashCode() {
return Objects.hash(firstName, lastName);
}

@Override
public String toString() {
String template = "UserDto{firstName='%s', lastName='%s'}";
return String.format(template, firstName, lastName);
}

@Override
public boolean isEmpty() {
return ObjectUtil.isEmptyOrNull(firstName)
&& ObjectUtil.isEmptyOrNull(lastName);
}
}
public record UserDto(
@Size(min = 2, max = 20) @NotBlank String firstName,
@Size(min = 2, max = 20) @NotBlank String lastName)
implements BaseResponse {}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,6 @@ public class CheckEndpoint {
@GetMapping(value = "/check", produces = MediaType.APPLICATION_JSON_VALUE)
public CheckVo check() {
log.info("nrbestapiVersion: {}", nrbestapiVersion);
return CheckVo.builder().message("OK").release(nrbestapiVersion).build();
return new CheckVo("OK", nrbestapiVersion);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,9 @@
import ca.bc.gov.backendstartapi.exception.UserExistsException;
import ca.bc.gov.backendstartapi.exception.UserNotFoundException;
import ca.bc.gov.backendstartapi.response.ExceptionResponse;
import ca.bc.gov.backendstartapi.response.FieldExceptionResponse;
import java.util.ArrayList;
import java.util.List;
import ca.bc.gov.backendstartapi.response.ValidationExceptionResponse;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
Expand All @@ -24,14 +21,10 @@ public class RestExceptionEndpoint {
* @return a Map of String containing all the invalid fields and messages
*/
@ExceptionHandler(MethodArgumentNotValidException.class)
ResponseEntity<ExceptionResponse> generalException(MethodArgumentNotValidException ex) {
ExceptionResponse exResponse = new ExceptionResponse(ex.getFieldErrors().size());
List<FieldExceptionResponse> fieldList = new ArrayList<>();
for (FieldError fe : ex.getFieldErrors()) {
fieldList.add(new FieldExceptionResponse(fe.getField(), fe.getDefaultMessage()));
}
exResponse.setFields(fieldList);
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(exResponse);
ResponseEntity<ValidationExceptionResponse> validationException(
MethodArgumentNotValidException ex) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST)
.body(new ValidationExceptionResponse(ex.getFieldErrors()));
}

/**
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import ca.bc.gov.backendstartapi.dto.UserDto;
import ca.bc.gov.backendstartapi.exception.UserExistsException;
import ca.bc.gov.backendstartapi.exception.UserNotFoundException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
Expand Down Expand Up @@ -41,16 +40,7 @@ public UserDto save(UserDto userDto) {
* @return a list with all possible users
*/
public List<UserDto> findAllByFirstName(String firstName) {
final List<UserDto> usersFound = new ArrayList<>();
users
.values()
.forEach(
dto -> {
if (dto.getFirstName().equals(firstName)) {
usersFound.add(dto);
}
});
return usersFound;
return users.values().stream().filter(user -> user.firstName().equals(firstName)).toList();
}

/**
Expand All @@ -60,16 +50,7 @@ public List<UserDto> findAllByFirstName(String firstName) {
* @return a list with all possible users
*/
public List<UserDto> findAllByLastName(String lastName) {
final List<UserDto> usersFound = new ArrayList<>();
users
.values()
.forEach(
dto -> {
if (dto.getLastName().equals(lastName)) {
usersFound.add(dto);
}
});
return usersFound;
return users.values().stream().filter(user -> user.lastName().equals(lastName)).toList();
}

/**
Expand All @@ -80,14 +61,8 @@ public List<UserDto> findAllByLastName(String lastName) {
* @return an Optional of UserDto if found, or Empty Optional otherwise.
*/
public Optional<UserDto> find(String firstName, String lastName) {
UserDto userDtoToFind = new UserDto(firstName, lastName);

UserDto userDb = users.get(userDtoToFind.hashCode());
if (Objects.isNull(userDb)) {
return Optional.empty();
}

return Optional.of(userDb);
UserDto userDb = users.get(new UserDto(firstName, lastName).hashCode());
return Optional.ofNullable(userDb);
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,32 +1,4 @@
package ca.bc.gov.backendstartapi.response;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import java.util.ArrayList;
import java.util.List;
import lombok.Getter;
import lombok.Setter;

/** This class represents any kind of exception that this API may go through. */
@Getter
@Setter
@JsonInclude(Include.NON_EMPTY)
public class ExceptionResponse {

private static final String MESSAGE_TEMPLATE = "%d field(s) with validation problem!";
private String errorMessage;
private List<FieldExceptionResponse> fields;

public ExceptionResponse() {
this(1);
}

public ExceptionResponse(int issuesCount) {
this(String.format(MESSAGE_TEMPLATE, issuesCount));
}

public ExceptionResponse(String errorMessage) {
this.errorMessage = errorMessage;
this.fields = new ArrayList<>();
}
}
public record ExceptionResponse(String errorMessage) {}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package ca.bc.gov.backendstartapi.response;

record FieldIssue(String fieldName, String fieldMessage) {}
Loading

0 comments on commit c25a663

Please sign in to comment.