Skip to content

Commit

Permalink
secureCodeBox#121 Reduce Coupling to Jackso by Extracting Mappers int…
Browse files Browse the repository at this point in the history
…o Own Object

Signed-off-by: Sven Strittmatter <[email protected]>
  • Loading branch information
Weltraumschaf committed Jul 3, 2024
1 parent 9797207 commit 190dfc7
Show file tree
Hide file tree
Showing 17 changed files with 72 additions and 38 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ protected Class<Endpoint> getModelClass() {
@Override
protected PaginatedResult<Endpoint> deserializeList(@NonNull String response) {
try {
return this.objectMapper.readValue(response, new TypeReference<>() {
return modelObjectMapper().readValue(response, new TypeReference<>() {
});
} catch (JsonProcessingException e) {
throw new PersistenceException("Can't process JSON response!", e);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ protected Class<Engagement> getModelClass() {
@Override
protected PaginatedResult<Engagement> deserializeList(@NonNull String response) {
try {
return this.objectMapper.readValue(response, new TypeReference<>() {
return modelObjectMapper().readValue(response, new TypeReference<>() {
});
} catch (JsonProcessingException e) {
throw new PersistenceException("Can't process JSON response!", e);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ protected Class<Finding> getModelClass() {
@Override
protected PaginatedResult<Finding> deserializeList(@NonNull String response) {
try {
return this.objectMapper.readValue(response, new TypeReference<>() {
return modelObjectMapper().readValue(response, new TypeReference<>() {
});
} catch (JsonProcessingException e) {
throw new PersistenceException("Can't process JSON response!", e);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,13 @@

package io.securecodebox.persistence.defectdojo.service;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.cfg.CoercionAction;
import com.fasterxml.jackson.databind.cfg.CoercionInputShape;
import io.securecodebox.persistence.defectdojo.config.ClientConfig;
import io.securecodebox.persistence.defectdojo.exception.TooManyResponsesException;
import io.securecodebox.persistence.defectdojo.http.AuthHeaderFactory;
import io.securecodebox.persistence.defectdojo.http.Foo;
import io.securecodebox.persistence.defectdojo.http.ProxyConfig;
import io.securecodebox.persistence.defectdojo.http.ProxyConfigFactory;
import io.securecodebox.persistence.defectdojo.model.Engagement;
import io.securecodebox.persistence.defectdojo.model.Model;
import io.securecodebox.persistence.defectdojo.model.PaginatedResult;
import lombok.NonNull;
Expand Down Expand Up @@ -46,9 +41,8 @@ abstract class GenericDefectDojoService<T extends Model> implements DefectDojoSe
private final ClientConfig clientConfig;
private final ProxyConfig proxyConfig;
private final RestTemplate restTemplate;
protected ObjectMapper objectMapper;
protected ObjectMapper searchStringMapper;

private final Mappers mapper = new Mappers();

/**
* Convenience constructor which initializes {@link #proxyConfig}
*
Expand All @@ -68,17 +62,6 @@ public GenericDefectDojoService(@NonNull ClientConfig clientConfig, @NonNull Pro
super();
this.clientConfig = clientConfig;
this.proxyConfig = proxyConfig;

this.objectMapper = new ObjectMapper();
this.objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
this.objectMapper.coercionConfigFor(Engagement.Status.class).setCoercion(CoercionInputShape.EmptyString, CoercionAction.AsNull);
this.objectMapper.findAndRegisterModules();

this.searchStringMapper = new ObjectMapper();
this.searchStringMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
this.searchStringMapper.coercionConfigFor(Engagement.Status.class).setCoercion(CoercionInputShape.EmptyString, CoercionAction.AsNull);
this.searchStringMapper.setSerializationInclusion(JsonInclude.Include.NON_DEFAULT);

this.restTemplate = this.setupRestTemplate();
}

Expand Down Expand Up @@ -112,10 +95,15 @@ public final List<T> search(@NonNull Map<String, Object> queryParams) {
do {
final var response = internalSearch(queryParams, DEFECT_DOJO_OBJET_LIMIT, DEFECT_DOJO_OBJET_LIMIT * page++);
objects.addAll(response.getResults());

hasNext = response.getNext() != null;

if (page > this.clientConfig.getMaxPageCountForGets()) {
throw new TooManyResponsesException("Found too many response object. Quitting after " + (page - 1) + " paginated API pages of " + DEFECT_DOJO_OBJET_LIMIT + " each.");
final var msg = String.format(
"Found too many response object. Quitting after %d paginated API pages of %d each.",
page - 1,
DEFECT_DOJO_OBJET_LIMIT
);
throw new TooManyResponsesException(msg);
}
} while (hasNext);

Expand All @@ -125,7 +113,8 @@ public final List<T> search(@NonNull Map<String, Object> queryParams) {
@Override
@SuppressWarnings("unchecked")
public final Optional<T> searchUnique(@NonNull T searchObject) {
final Map<String, Object> queryParams = searchStringMapper.convertValue(searchObject, Map.class);
final Map<String, Object> queryParams = mapper.searchStringMapper()
.convertValue(searchObject, Map.class);
final var objects = search(queryParams);

return objects.stream()
Expand Down Expand Up @@ -198,6 +187,11 @@ final URI createBaseUrl() {
return URI.create(buffer).normalize();
}

final ObjectMapper modelObjectMapper() {
// We only expose this mapper to subclasses.
return mapper.modelObjectMapper();
}

private HttpHeaders createAuthorizationHeaders() {
final var factory = new AuthHeaderFactory(clientConfig);
factory.setProxyConfig(proxyConfig);
Expand All @@ -207,7 +201,7 @@ private HttpHeaders createAuthorizationHeaders() {
private RestTemplate setupRestTemplate() {
final RestTemplate template = new Foo(new ProxyConfigFactory().create()).createRestTemplate();
final MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
converter.setObjectMapper(this.objectMapper);
converter.setObjectMapper(mapper.modelObjectMapper());
template.setMessageConverters(List.of(
new FormHttpMessageConverter(),
new ResourceHttpMessageConverter(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ protected Class<GroupMember> getModelClass() {
@Override
protected PaginatedResult<GroupMember> deserializeList(@NonNull String response) {
try {
return this.objectMapper.readValue(response, new TypeReference<>() {
return modelObjectMapper().readValue(response, new TypeReference<>() {
});
} catch (JsonProcessingException e) {
throw new PersistenceException("Can't process JSON response!", e);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ protected Class<Group> getModelClass() {
@Override
protected PaginatedResult<Group> deserializeList(@NonNull String response) {
try {
return this.objectMapper.readValue(response, new TypeReference<>() {
return modelObjectMapper().readValue(response, new TypeReference<>() {
});
} catch (JsonProcessingException e) {
throw new PersistenceException("Can't process JSON response!", e);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package io.securecodebox.persistence.defectdojo.service;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.cfg.CoercionAction;
import com.fasterxml.jackson.databind.cfg.CoercionInputShape;
import io.securecodebox.persistence.defectdojo.model.Engagement;
import lombok.Getter;
import lombok.experimental.Accessors;

/**
* Provides pre configured Jackson mappers
*/
@Getter
@Accessors(fluent = true)
final class Mappers {
private final ObjectMapper modelObjectMapper = new ObjectMapper();
private final ObjectMapper searchStringMapper = new ObjectMapper();

Mappers() {
super();
configureModelObjectMapper();
configureSearchStringMapper();
}

private void configureModelObjectMapper() {
modelObjectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
modelObjectMapper.coercionConfigFor(Engagement.Status.class)
.setCoercion(CoercionInputShape.EmptyString, CoercionAction.AsNull);
modelObjectMapper.findAndRegisterModules();
}

private void configureSearchStringMapper() {
searchStringMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
searchStringMapper.coercionConfigFor(Engagement.Status.class)
.setCoercion(CoercionInputShape.EmptyString, CoercionAction.AsNull);
searchStringMapper.setSerializationInclusion(JsonInclude.Include.NON_DEFAULT);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ protected Class<ProductGroup> getModelClass() {
@Override
protected PaginatedResult<ProductGroup> deserializeList(@NonNull String response) {
try {
return this.objectMapper.readValue(response, new TypeReference<>() {
return modelObjectMapper().readValue(response, new TypeReference<>() {
});
} catch (JsonProcessingException e) {
throw new PersistenceException("Can't process JSON response!", e);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ protected Class<Product> getModelClass() {
@Override
protected PaginatedResult<Product> deserializeList(@NonNull String response) {
try {
return this.objectMapper.readValue(response, new TypeReference<>() {
return modelObjectMapper().readValue(response, new TypeReference<>() {
});
} catch (JsonProcessingException e) {
throw new PersistenceException("Can't process JSON response!", e);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ protected Class<ProductType> getModelClass() {
@Override
protected PaginatedResult<ProductType> deserializeList(@NonNull String response) {
try {
return this.objectMapper.readValue(response, new TypeReference<>() {
return modelObjectMapper().readValue(response, new TypeReference<>() {
});
} catch (JsonProcessingException e) {
throw new PersistenceException("Can't process JSON response!", e);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ protected Class<Test> getModelClass() {
@Override
protected PaginatedResult<Test> deserializeList(@NonNull String response) {
try {
return this.objectMapper.readValue(response, new TypeReference<>() {
return modelObjectMapper().readValue(response, new TypeReference<>() {
});
} catch (JsonProcessingException e) {
throw new PersistenceException("Can't process JSON response!", e);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ protected Class<TestType> getModelClass() {
@Override
protected PaginatedResult<TestType> deserializeList(@NonNull String response) {
try {
return this.objectMapper.readValue(response, new TypeReference<>() {
return modelObjectMapper().readValue(response, new TypeReference<>() {
});
} catch (JsonProcessingException e) {
throw new PersistenceException("Can't process JSON response!", e);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ protected Class<ToolConfig> getModelClass() {
@Override
protected PaginatedResult<ToolConfig> deserializeList(@NonNull String response) {
try {
return this.objectMapper.readValue(response, new TypeReference<>() {
return modelObjectMapper().readValue(response, new TypeReference<>() {
});
} catch (JsonProcessingException e) {
throw new PersistenceException("Can't process JSON response!", e);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ protected Class<ToolType> getModelClass() {
@Override
protected PaginatedResult<ToolType> deserializeList(@NonNull String response) {
try {
return this.objectMapper.readValue(response, new TypeReference<>() {
return modelObjectMapper().readValue(response, new TypeReference<>() {
});
} catch (JsonProcessingException e) {
throw new PersistenceException("Can't process JSON response!", e);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ protected PaginatedResult<UserProfile> deserializeList(@NonNull String response)
*/
final UserProfile userProfile;
try {
userProfile = this.objectMapper.readValue(response, new TypeReference<UserProfile>() {
userProfile = modelObjectMapper().readValue(response, new TypeReference<>() {
});
} catch (JsonProcessingException e) {
throw new PersistenceException("Can't process JSON response!", e);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ protected Class<User> getModelClass() {
@Override
protected PaginatedResult<User> deserializeList(@NonNull String response) {
try {
return this.objectMapper.readValue(response, new TypeReference<>() {
return modelObjectMapper().readValue(response, new TypeReference<>() {
});
} catch (JsonProcessingException e) {
throw new PersistenceException("Can't process JSON response!", e);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ protected Class<TestModel> getModelClass() {
@Override
@SneakyThrows
protected PaginatedResult<TestModel> deserializeList(@NonNull String response) {
return this.objectMapper.readValue(response, new TypeReference<>() {
return modelObjectMapper().readValue(response, new TypeReference<>() {
});
}
}
Expand Down

0 comments on commit 190dfc7

Please sign in to comment.