Skip to content
Snippets Groups Projects
Commit 258e4339 authored by OZGCloud's avatar OZGCloud
Browse files

OZG-1701 parse json, map to eingang data

parent 3c7e6f6d
Branches
Tags
No related merge requests found
Showing
with 541 additions and 10 deletions
...@@ -16,21 +16,19 @@ import lombok.ToString; ...@@ -16,21 +16,19 @@ import lombok.ToString;
public class FormData { public class FormData {
@NotNull @NotNull
private UUID id; @Builder.Default
private UUID id = UUID.randomUUID();
private FormHeader header; private FormHeader header;
private ZustaendigeStelle zustaendigeStelle; private ZustaendigeStelle zustaendigeStelle;
private Antragsteller antragsteller; private Antragsteller antragsteller;
private Map<String, Object> formData; private Map<String, Object> formData;
private List<IncomingFileGroup> attachments;
private int numberOfAttachments; private int numberOfAttachments;
private List<IncomingFileGroup> attachments;
private List<IncomingFile> representations;
private int numberOfRepresentations; private int numberOfRepresentations;
private List<IncomingFile> representations;
} }
...@@ -15,7 +15,8 @@ public class FormHeader { ...@@ -15,7 +15,8 @@ public class FormHeader {
private String requestId; private String requestId;
private ZonedDateTime createdAt; @Builder.Default
private ZonedDateTime createdAt = ZonedDateTime.now();
private String formId; private String formId;
...@@ -24,10 +25,8 @@ public class FormHeader { ...@@ -24,10 +25,8 @@ public class FormHeader {
private String sender; private String sender;
private String customer; private String customer;
private String customerId; private String customerId;
private String client; private String client;
private String clientId; private String clientId;
} }
...@@ -37,6 +37,10 @@ ...@@ -37,6 +37,10 @@
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId> <artifactId>spring-boot-starter-actuator</artifactId>
</dependency> </dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-json</artifactId>
</dependency>
<!-- tag::springws[] --> <!-- tag::springws[] -->
<dependency> <dependency>
......
package de.itvsh.kop.eingangsadapter.formsolutions;
import java.util.List;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Builder;
import lombok.Getter;
@Getter
@Builder
class EingangData {
@JsonProperty("assistant")
private FsFormData formData;
private byte[] pdf;
}
@Getter
@Builder
class FsFormData {
private String identifier;
private List<FsPanel> panels;
}
@Getter
@Builder
class FsPanel {
private String identifier;
private List<FsComponent> components;
}
@Getter
@JsonIgnoreProperties("needed")
@Builder
class FsComponent {
private String identifier;
@JsonProperty("stringValue")
private String value;
private List<FsComponent> components;
}
\ No newline at end of file
package de.itvsh.kop.eingangsadapter.formsolutions;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.NullValueCheckStrategy;
import de.itvsh.kop.eingangsadapter.common.formdata.FormData;
import de.itvsh.kop.eingangsadapter.common.formdata.FormHeader;
import de.itvsh.kop.eingangsadapter.common.formdata.IncomingFile;
@Mapper(nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS)
interface EingangDataMapper {
static final Predicate<FsComponent> HAS_CONTENT = component -> Objects.nonNull(component.getComponents())
|| Objects.nonNull(component.getValue());
static final Predicate<FsComponent> IS_NODE_COMPONENT = component -> Objects.isNull(component.getComponents());
static final String FILE_NAME_PDF_REP = "eingang.pdf";
static final String PDF_CONTENT_TYPE = "application/pdf";
@Mapping(target = "id", ignore = true)
@Mapping(target = "antragsteller", ignore = true)
@Mapping(target = "zustaendigeStelle", ignore = true)
@Mapping(target = "attachments", ignore = true)
@Mapping(target = "numberOfAttachments", ignore = true)
@Mapping(target = "representations", expression = "java(mapPdfRepresentation(data.getPdf()))")
@Mapping(target = "numberOfRepresentations", constant = "1")
@Mapping(target = "header", expression = "java(mapHeader(data))")
FormData mapToFormData(EingangData data);
default Map<String, Object> mapFormData(FsFormData formData) {
return Map.of(formData.getIdentifier(), mapPanels(formData.getPanels()));
}
default Map<String, Object> mapPanels(List<FsPanel> panels) {
return panels.stream().collect(Collectors.toMap(FsPanel::getIdentifier, p -> mapComponents(p.getComponents())));
}
default Map<String, Object> mapComponents(List<FsComponent> components) {
return components.stream().filter(HAS_CONTENT).collect(Collectors.toMap(FsComponent::getIdentifier, this::mapComponent));
}
default Object mapComponent(FsComponent component) {
if (IS_NODE_COMPONENT.test(component)) {
return component.getValue();
} else {
return mapComponents(component.getComponents());
}
}
default List<IncomingFile> mapPdfRepresentation(byte[] pdf) {
if (Objects.isNull(pdf) || pdf.length == 0) {
return Collections.emptyList();
}
return List.of(IncomingFile.builder()
.content(pdf)
.contentType(PDF_CONTENT_TYPE)
.size(pdf.length)
.name(FILE_NAME_PDF_REP)
.build());
}
default FormHeader mapHeader(EingangData data) {
return FormHeader.builder()
.formName(data.getFormData().getIdentifier())
.build();
}
}
package de.itvsh.kop.eingangsadapter.formsolutions; package de.itvsh.kop.eingangsadapter.formsolutions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.ws.server.endpoint.annotation.Endpoint; import org.springframework.ws.server.endpoint.annotation.Endpoint;
import org.springframework.ws.server.endpoint.annotation.PayloadRoot; import org.springframework.ws.server.endpoint.annotation.PayloadRoot;
import org.springframework.ws.server.endpoint.annotation.RequestPayload; import org.springframework.ws.server.endpoint.annotation.RequestPayload;
import org.springframework.ws.server.endpoint.annotation.ResponsePayload; import org.springframework.ws.server.endpoint.annotation.ResponsePayload;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import de.itvsh.kop.eingangsadapter.common.errorhandling.TechnicalException;
import de.itvsh.kop.eingangsadapter.router.VorgangService;
@Endpoint @Endpoint
public class SendFormEndpoint { public class SendFormEndpoint {
@Autowired
private ObjectMapper objectMapper;
@Autowired
private EingangDataMapper mapper;
@Autowired
private VorgangService service;
@PayloadRoot(namespace = WebServiceConfiguration.NAMESPACE_URI, localPart = "Request") @PayloadRoot(namespace = WebServiceConfiguration.NAMESPACE_URI, localPart = "Request")
@ResponsePayload @ResponsePayload
public Response receiveForm(@RequestPayload Request request) { public Response receiveForm(@RequestPayload Request request) {
service.createVorgang(mapper.mapToFormData(parseJsonData(request.getJSON())));
return buildSuccessResponse(); return buildSuccessResponse();
} }
EingangData parseJsonData(String jsonData) {
try {
return objectMapper.readValue(jsonData, EingangData.class);
} catch (JsonProcessingException e) {
throw new TechnicalException("Error parsing JSON from FromSolutions-Server: " + e.getCause().getMessage(), e);
}
}
private Response buildSuccessResponse() { private Response buildSuccessResponse() {
var response = new Response(); var response = new Response();
......
package de.itvsh.kop.eingangsadapter.formsolutions;
import static org.assertj.core.api.Assertions.*;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.*;
import java.util.List;
import java.util.Map;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.mapstruct.factory.Mappers;
import de.itvsh.kop.eingangsadapter.common.formdata.IncomingFile;
import de.itvsh.kop.eingangsadapter.common.formdata.IncomingFileTestFactory;
class EingangDataMapperTest {
private EingangDataMapper mapper = spy(Mappers.getMapper(EingangDataMapper.class));
@Nested
class MapComponents {
@Test
void mapNodeComponent() {
var map = mapper.mapComponents(List.of(FsComponentTestFactory.createNode()));
assertThat(map).containsEntry(FsComponentTestFactory.NODE_IDENTIFIER, FsComponentTestFactory.VALUE);
}
@Test
void mapGroupComponent() {
var map = mapper.mapComponents(List.of(FsComponentTestFactory.createGroup()));
assertThat(map).containsKey(FsComponentTestFactory.GROUP_IDENTIFIER);
@SuppressWarnings("unchecked")
var subMap = (Map<String, Object>) map.get(FsComponentTestFactory.GROUP_IDENTIFIER);
assertThat(subMap).containsEntry(FsComponentTestFactory.NODE_IDENTIFIER, FsComponentTestFactory.VALUE);
}
}
@Nested
class MapPanels {
@Test
void shoudContainIdentifier() {
var map = mapper.mapPanels(List.of(FsPanelTestFactory.create()));
assertThat(map).containsKey(FsPanelTestFactory.IDENTIFIER);
}
@Test
void shouldMapComponents() {
mapper.mapPanels(List.of(FsPanelTestFactory.create()));
verify(mapper, times(2)).mapComponents(anyList());
}
}
@Nested
class MapFormData {
@Test
void shouldContainIdentifier() {
var map = mapper.mapFormData(FsFormDataTestFactory.create());
assertThat(map).containsKey(FsFormDataTestFactory.IDENTIFIER);
}
@Test
void shouldMapPanel() {
mapper.mapFormData(FsFormDataTestFactory.create());
verify(mapper).mapPanels(anyList());
}
}
@Nested
class MapPdfRepresentation {
@Test
void shouldHaveRepresentation() {
var formData = mapper.mapToFormData(EingangDataTestFactory.create());
assertThat(formData.getRepresentations()).hasSize(1);
}
@Test
void shouldHaveName() {
var file = mapAndGetFile();
assertThat(file.getName()).isEqualTo(EingangDataMapper.FILE_NAME_PDF_REP);
}
@Test
void shouldHaveContent() {
var file = mapAndGetFile();
assertThat(file.getContent()).isEqualTo(IncomingFileTestFactory.CONTENT);
}
@Test
void shouldHaveContentType() {
var file = mapAndGetFile();
assertThat(file.getContentType()).isEqualTo(EingangDataMapper.PDF_CONTENT_TYPE);
}
@Test
void shouldHaveSize() {
var file = mapAndGetFile();
assertThat(file.getSize()).isEqualTo(IncomingFileTestFactory.SIZE);
}
@Test
void numberShoultBeOne() {
var formData = mapper.mapToFormData(EingangDataTestFactory.create());
assertThat(formData.getNumberOfRepresentations()).isEqualTo(1);
}
private IncomingFile mapAndGetFile() {
return mapper.mapToFormData(EingangDataTestFactory.create()).getRepresentations().get(0);
}
}
}
package de.itvsh.kop.eingangsadapter.formsolutions;
import de.itvsh.kop.eingangsadapter.common.formdata.IncomingFileTestFactory;
class EingangDataTestFactory {
static final EingangData create() {
return createBuilder().build();
}
static final EingangData.EingangDataBuilder createBuilder() {
return EingangData.builder()
.formData(FsFormDataTestFactory.create())
.pdf(IncomingFileTestFactory.CONTENT);
}
}
package de.itvsh.kop.eingangsadapter.formsolutions;
import java.util.List;
class FsComponentTestFactory {
public static final String NODE_IDENTIFIER = "Name";
public static final String GROUP_IDENTIFIER = "Kontakt";
public static final String VALUE = "Theo Test";
static FsComponent createNode() {
return createNodeBuilder().build();
}
static FsComponent.FsComponentBuilder createNodeBuilder() {
return FsComponent.builder()
.identifier(NODE_IDENTIFIER)
.value(VALUE);
}
static FsComponent createGroup() {
return createGroupBuilder().build();
}
static FsComponent.FsComponentBuilder createGroupBuilder() {
return FsComponent.builder()
.identifier(GROUP_IDENTIFIER)
.components(List.of(createNode()));
}
}
package de.itvsh.kop.eingangsadapter.formsolutions;
import java.util.List;
class FsFormDataTestFactory {
public static final String IDENTIFIER = "Hamsterschein";
static FsFormData create() {
return createBuilder().build();
}
static FsFormData.FsFormDataBuilder createBuilder() {
return FsFormData.builder()
.identifier(IDENTIFIER)
.panels(List.of(FsPanelTestFactory.create()));
}
}
package de.itvsh.kop.eingangsadapter.formsolutions;
import java.util.List;
class FsPanelTestFactory {
static final String IDENTIFIER = "Kontaktdaten";
static FsPanel create() {
return createBuilder().build();
}
static FsPanel.FsPanelBuilder createBuilder() {
return FsPanel.builder()
.identifier(IDENTIFIER)
.components(List.of(FsComponentTestFactory.createGroup()));
}
}
package de.itvsh.kop.eingangsadapter.formsolutions;
import static org.assertj.core.api.Assertions.*;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ActiveProfiles;
@SpringBootTest
@ActiveProfiles({ "local", "itcase" })
class SendFormEndpointITCase {
@Autowired
private SendFormEndpoint endpoint;
@Nested
class ParseSimpleJsonData {
private final String simpleJsonData = """
{
"assistant": {
"identifier": "AS_123",
"panels": [{
"identifier": "Panel_0_1",
"components": [
{
"identifier": "Textfeld (einzeilig)",
"needed": true,
"stringValue": "kfjhkfjhk"
},
{
"identifier": "Datums- / Uhrzeitfeld",
"needed": true,
"stringValue": "22.05.1996"
}
]}
]
}
}""";
@Test
void shouldParseData() {
var parsed = endpoint.parseJsonData(simpleJsonData);
assertThat(parsed).isNotNull();
}
@Test
void shouldContainEingangData() {
var parsed = endpoint.parseJsonData(simpleJsonData);
assertThat(parsed.getFormData()).isNotNull();
}
@Nested
class WithPanels {
@Test
void shouldContainPanel() {
var parsed = endpoint.parseJsonData(simpleJsonData);
assertThat(parsed.getFormData().getPanels()).hasSize(1);
}
@Test
void shouldHaveIdentifier() {
var panel = parseAndGetPanel();
assertThat(panel.getIdentifier()).isEqualTo("Panel_0_1");
}
@Test
void shouldHaveComponents() {
var panel = parseAndGetPanel();
assertThat(panel.getComponents()).hasSize(2);
}
}
private FsPanel parseAndGetPanel() {
return SendFormEndpointITCase.this.parseAndGetPanel(simpleJsonData);
}
}
@Nested
class ParseNestedComponents {
// TODO move to file when TestUtils available
private final String nestedComponents = """
{
"assistant": {
"identifier": "AS_123",
"panels": [{
"identifier": "Panel_0_1",
"components": [{
"identifier": "Objektgruppe[0]",
"needed": true,
"components": [
{
"identifier": "Datums- / Uhrzeitfeld",
"needed": true,
"stringValue": "22.05.1996"
}
]
}]
}]
}
}""";
@Test
void shouldParseData() {
var parsed = endpoint.parseJsonData(nestedComponents);
assertThat(parsed).isNotNull();
}
@Test
void shouldHaveComponents() {
var panel = parseAndGetPanel();
assertThat(panel.getComponents()).hasSize(1);
}
@Test
void shouldHaveIdentifier() {
var component = parseAndGetComponent();
assertThat(component.getIdentifier()).isEqualTo("Objektgruppe[0]");
}
@Test
void shouldHaveNestedComponents() {
var component = parseAndGetComponent();
assertThat(component.getComponents()).hasSize(1);
assertThat(component.getValue()).isNull();
}
private FsComponent parseAndGetComponent() {
return parseAndGetPanel().getComponents().get(0);
}
private FsPanel parseAndGetPanel() {
return SendFormEndpointITCase.this.parseAndGetPanel(nestedComponents);
}
}
@Nested
class ParsePdfRepresentation {
// TODO move to file when TestUtils available
private final String pdfRepresentation = """
{
"assistant":{},
"pdf":"TG9yZW0gaXBzdW0="
}
""";
@Test
void shouldHavePdf() {
var parsed = endpoint.parseJsonData(pdfRepresentation);
assertThat(parsed.getPdf()).isNotNull().isEqualTo("Lorem ipsum".getBytes());
}
}
private FsPanel parseAndGetPanel(String json) {
return endpoint.parseJsonData(json).getFormData().getPanels().get(0);
}
}
spring:
jackson:
deserialization:
fail-on-unknown-properties: true
\ No newline at end of file
...@@ -144,7 +144,7 @@ ...@@ -144,7 +144,7 @@
-Amapstruct.defaultComponentModel=spring -Amapstruct.defaultComponentModel=spring
</compilerArg> </compilerArg>
<compilerArg> <compilerArg>
-Amapstruct.unmappedTargetPolicy=IGNORE -Amapstruct.unmappedTargetPolicy=WARN
</compilerArg> </compilerArg>
</compilerArgs> </compilerArgs>
</configuration> </configuration>
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment