diff --git a/.gitignore b/.gitignore
index 8b6c1c386122d1f8e835ffe797eab68b340c88ae..b5e3b3eb7880f6430da0193ef5916d86e8e99808 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,4 +2,5 @@ target/
.settings/
.project
.classpath
-bin/
\ No newline at end of file
+bin/
+.vscode/
\ No newline at end of file
diff --git a/persistence/runtime/pom.xml b/persistence/runtime/pom.xml
index 85d8fd5e3da5b46748fc35def7afa0bf7999a49e..636f33decc6dece653c14bba13e9c643faa2500c 100644
--- a/persistence/runtime/pom.xml
+++ b/persistence/runtime/pom.xml
@@ -8,11 +8,15 @@
quarkus-persistence
Persistence - Runtime
+
+ 1.5.2.Final
+ 1.8.2
+
org.eclipsefoundation
quarkus-core
- ${project.version}
+ ${project.version}
io.quarkus
@@ -30,6 +34,11 @@
org.apache.commons
commons-lang3
+
+ org.mapstruct
+ mapstruct
+ ${org.mapstruct.version}
+
@@ -57,6 +66,24 @@
h2
test
+
+
+
+ com.google.auto.value
+ auto-value
+ ${auto-value.version}
+ provided
+
+
+ com.google.auto.value
+ auto-value-annotations
+ ${auto-value.version}
+
+
+ com.google.code.findbugs
+ jsr305
+
+
@@ -75,7 +102,7 @@
-
+
maven-compiler-plugin
@@ -85,6 +112,16 @@
quarkus-extension-processor
${quarkus.version}
+
+ org.mapstruct
+ mapstruct-processor
+ ${org.mapstruct.version}
+
+
+ com.google.auto.value
+ auto-value
+ ${auto-value.version}
+
diff --git a/persistence/runtime/src/main/java/org/eclipsefoundation/persistence/config/QuarkusMappingConfig.java b/persistence/runtime/src/main/java/org/eclipsefoundation/persistence/config/QuarkusMappingConfig.java
new file mode 100644
index 0000000000000000000000000000000000000000..37b0c4fa67d6c12dc520d48509efabe2d44d5a4e
--- /dev/null
+++ b/persistence/runtime/src/main/java/org/eclipsefoundation/persistence/config/QuarkusMappingConfig.java
@@ -0,0 +1,17 @@
+/*********************************************************************
+* Copyright (c) 2022 Eclipse Foundation
+*
+* This program and the accompanying materials are made
+* available under the terms of the Eclipse Public License 2.0
+* which is available at https://www.eclipse.org/legal/epl-2.0/
+*
+* SPDX-License-Identifier: EPL-2.0
+**********************************************************************/
+package org.eclipsefoundation.persistence.config;
+
+import org.mapstruct.MapperConfig;
+
+@MapperConfig(componentModel = "cdi")
+public interface QuarkusMappingConfig {
+
+}
diff --git a/persistence/runtime/src/main/java/org/eclipsefoundation/persistence/dto/mapper/EntityMapper.java b/persistence/runtime/src/main/java/org/eclipsefoundation/persistence/dto/mapper/EntityMapper.java
new file mode 100644
index 0000000000000000000000000000000000000000..9b6b13d2eff626ee4df6fe601b0241218b7e2e7a
--- /dev/null
+++ b/persistence/runtime/src/main/java/org/eclipsefoundation/persistence/dto/mapper/EntityMapper.java
@@ -0,0 +1,40 @@
+/*********************************************************************
+* Copyright (c) 2022 Eclipse Foundation
+*
+* This program and the accompanying materials are made
+* available under the terms of the Eclipse Public License 2.0
+* which is available at https://www.eclipse.org/legal/epl-2.0/
+*
+* SPDX-License-Identifier: EPL-2.0
+**********************************************************************/
+package org.eclipsefoundation.persistence.dto.mapper;
+
+import org.eclipsefoundation.persistence.dto.BareNode;
+import org.mapstruct.InheritInverseConfiguration;
+
+/**
+ * Mapper interface to allow mapping of DTOs and Models
+ *
+ * @author Zachary Sabourin
+ */
+public interface EntityMapper {
+
+ S toModel(T dtoEntity);
+
+ @InheritInverseConfiguration
+ T toDTO(S model);
+
+ /**
+ * Returns the mapped DTO type.
+ *
+ * @return the class of mapped DTO
+ */
+ Class getDTOType();
+
+ /**
+ * Returns the mapped model type.
+ *
+ * @return the class of mapped model
+ */
+ Class getModelType();
+}
diff --git a/persistence/runtime/src/main/java/org/eclipsefoundation/persistence/service/MapperService.java b/persistence/runtime/src/main/java/org/eclipsefoundation/persistence/service/MapperService.java
new file mode 100644
index 0000000000000000000000000000000000000000..5eb74dbd4d371a4943500f1f67d143206b0a93f9
--- /dev/null
+++ b/persistence/runtime/src/main/java/org/eclipsefoundation/persistence/service/MapperService.java
@@ -0,0 +1,40 @@
+/*********************************************************************
+* Copyright (c) 2022 Eclipse Foundation
+*
+* This program and the accompanying materials are made
+* available under the terms of the Eclipse Public License 2.0
+* which is available at https://www.eclipse.org/legal/epl-2.0/
+*
+* SPDX-License-Identifier: EPL-2.0
+**********************************************************************/
+package org.eclipsefoundation.persistence.service;
+
+import org.eclipsefoundation.persistence.dto.BareNode;
+import org.eclipsefoundation.persistence.dto.mapper.EntityMapper;
+
+/**
+ * MapperService interface to allow retrieval of a corresponding EntityMapper.
+ * Can retrieve an EntityMapper based on target DTO or model class.
+ *
+ * @author Zachary Sabourin
+ */
+public interface MapperService {
+
+ /**
+ * Method to allow retrieval of EntityMapper that corresponds to the target
+ * model class.
+ *
+ * @param target The target class used for EntityMapper retrieval
+ * @return A reference to the target EntityMapper
+ */
+ EntityMapper getByModel(Class target);
+
+ /**
+ * Method to allow retrieval of EntityMapper that corresponds to the target
+ * DTO class.
+ *
+ * @param target The target class used for EntityMapper retrieval
+ * @return A reference to the target EntityMapper
+ */
+ EntityMapper getByDTO(Class target);
+}
diff --git a/persistence/runtime/src/main/java/org/eclipsefoundation/persistence/service/impl/DefaultMapperService.java b/persistence/runtime/src/main/java/org/eclipsefoundation/persistence/service/impl/DefaultMapperService.java
new file mode 100644
index 0000000000000000000000000000000000000000..19666875d95f88c174ecfd4b9bdd870c54d262cc
--- /dev/null
+++ b/persistence/runtime/src/main/java/org/eclipsefoundation/persistence/service/impl/DefaultMapperService.java
@@ -0,0 +1,61 @@
+/*********************************************************************
+* Copyright (c) 2022 Eclipse Foundation
+*
+* This program and the accompanying materials are made
+* available under the terms of the Eclipse Public License 2.0
+* which is available at https://www.eclipse.org/legal/epl-2.0/
+*
+* SPDX-License-Identifier: EPL-2.0
+**********************************************************************/
+package org.eclipsefoundation.persistence.service.impl;
+
+import javax.enterprise.context.ApplicationScoped;
+import javax.enterprise.inject.Instance;
+import javax.inject.Inject;
+
+import org.eclipsefoundation.persistence.dto.BareNode;
+import org.eclipsefoundation.persistence.dto.mapper.EntityMapper;
+import org.eclipsefoundation.persistence.service.MapperService;
+
+/**
+ * Indicates an entity mapping between DTOs and models
+ *
+ * @author Zachary Sabourin
+ *
+ * @param the DTO object in the mapping pair
+ * @param the model object in the mapping pair
+ */
+@ApplicationScoped
+public class DefaultMapperService implements MapperService {
+
+ @Inject
+ Instance> mappers;
+
+ /**
+ * Retrieves an instance of EntityMapper that corresponds to the target model
+ * class.
+ *
+ * @param target The target class used for EntityMapper retrieval
+ * @return A reference to the target EntityMapper if it exists
+ */
+ @Override
+ @SuppressWarnings("unchecked")
+ public EntityMapper getByModel(Class target) {
+ return (EntityMapper) mappers.stream().filter(map -> map.getModelType().equals(target))
+ .findFirst().orElse(null);
+ }
+
+ /**
+ * Retrieves an instance of EntityMapper that corresponds to the target DTO
+ * class.
+ *
+ * @param target The target class used for EntityMapper retrieval
+ * @return A reference to the target EntityMapper if it exists
+ */
+ @Override
+ @SuppressWarnings("unchecked")
+ public EntityMapper getByDTO(Class target) {
+ return (EntityMapper) mappers.stream().filter(map -> map.getDTOType().equals(target))
+ .findFirst().orElse(null);
+ }
+}
diff --git a/persistence/runtime/src/test/java/org/eclipsefoundation/persistence/service/MapperServiceTest.java b/persistence/runtime/src/test/java/org/eclipsefoundation/persistence/service/MapperServiceTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..598dd8753b1807b88e8461d9342f00a5f7ce822c
--- /dev/null
+++ b/persistence/runtime/src/test/java/org/eclipsefoundation/persistence/service/MapperServiceTest.java
@@ -0,0 +1,97 @@
+/*********************************************************************
+* Copyright (c) 2022 Eclipse Foundation
+*
+* This program and the accompanying materials are made
+* available under the terms of the Eclipse Public License 2.0
+* which is available at https://www.eclipse.org/legal/epl-2.0/
+*
+* SPDX-License-Identifier: EPL-2.0
+**********************************************************************/
+package org.eclipsefoundation.persistence.service;
+
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import javax.inject.Inject;
+
+import org.eclipsefoundation.persistence.test.dto.PersonDTO;
+import org.eclipsefoundation.persistence.test.model.PersonModel;
+import org.junit.jupiter.api.Test;
+
+import io.quarkus.test.junit.QuarkusTest;
+
+/**
+ * Tests the MapperService by attempting to retrieve a Mapper by model and DTO.
+ * Tests that the retrieved Mapper converts properly in both directions.
+ *
+ * @author Zachary Sabourin
+ */
+@QuarkusTest
+public class MapperServiceTest {
+
+ @Inject
+ MapperService mapperService;
+
+ @Test
+ public void getMapperByModel() {
+ assertTrue(mapperService.getByModel(PersonModel.class) != null);
+ assertTrue(mapperService.getByModel(PersonModel.class).getDTOType() == PersonDTO.class);
+ }
+
+ @Test
+ public void getMapperByDTO() {
+ assertTrue(mapperService.getByDTO(PersonDTO.class) != null);
+ assertTrue(mapperService.getByDTO(PersonDTO.class).getModelType() == PersonModel.class);
+ }
+
+ @Test
+ public void convertToDTO_mapperByModel() {
+ PersonModel personModel = PersonModel.builder().setAge(25).setName("JimBob").setPersonID("TM-50").build();
+
+ PersonDTO personDTO = mapperService.getByModel(PersonModel.class).toDTO(personModel);
+
+ assertTrue(personModel.getPersonID().equals(personDTO.getId()));
+ assertTrue(personModel.getName().equals(personDTO.getName()));
+ assertTrue(personModel.getAge() == personDTO.getAge());
+ }
+
+ @Test
+ public void convertToDTO_mapperByDTO() {
+ PersonModel personModel = PersonModel.builder().setAge(25).setName("JimBob").setPersonID("TM-50").build();
+
+ PersonDTO personDTO = mapperService.getByDTO(PersonDTO.class).toDTO(personModel);
+
+ assertTrue(personModel.getPersonID().equals(personDTO.getId()));
+ assertTrue(personModel.getName().equals(personDTO.getName()));
+ assertTrue(personModel.getAge() == personDTO.getAge());
+ }
+
+ @Test
+ public void convertToModel_mapperbyModel() {
+
+ PersonDTO personDTO = new PersonDTO();
+ personDTO.setPersonID("TM-50");
+ personDTO.setName("JimBob");
+ personDTO.setAge(25);
+
+ PersonModel personModel = mapperService.getByModel(PersonModel.class).toModel(personDTO);
+
+ assertTrue(personModel.getPersonID().equals(personDTO.getId()));
+ assertTrue(personModel.getName().equals(personDTO.getName()));
+ assertTrue(personModel.getAge() == personDTO.getAge());
+ }
+
+ @Test
+ public void convertToModel_mapperbyDTO() {
+
+ PersonDTO personDTO = new PersonDTO();
+ personDTO.setPersonID("TM-50");
+ personDTO.setName("JimBob");
+ personDTO.setAge(25);
+
+ PersonModel personModel = mapperService.getByDTO(PersonDTO.class).toModel(personDTO);
+
+ assertTrue(personModel.getPersonID().equals(personDTO.getId()));
+ assertTrue(personModel.getName().equals(personDTO.getName()));
+ assertTrue(personModel.getAge() == personDTO.getAge());
+ }
+}
diff --git a/persistence/runtime/src/test/java/org/eclipsefoundation/persistence/service/dto/mapper/PersonMapper.java b/persistence/runtime/src/test/java/org/eclipsefoundation/persistence/service/dto/mapper/PersonMapper.java
new file mode 100644
index 0000000000000000000000000000000000000000..af695a719e9cca7ac8dac8bd737f3f2493d4a5f9
--- /dev/null
+++ b/persistence/runtime/src/test/java/org/eclipsefoundation/persistence/service/dto/mapper/PersonMapper.java
@@ -0,0 +1,40 @@
+/*********************************************************************
+* Copyright (c) 2022 Eclipse Foundation
+*
+* This program and the accompanying materials are made
+* available under the terms of the Eclipse Public License 2.0
+* which is available at https://www.eclipse.org/legal/epl-2.0/
+*
+* SPDX-License-Identifier: EPL-2.0
+**********************************************************************/
+package org.eclipsefoundation.persistence.service.dto.mapper;
+
+import org.eclipsefoundation.persistence.config.QuarkusMappingConfig;
+import org.eclipsefoundation.persistence.dto.mapper.EntityMapper;
+import org.eclipsefoundation.persistence.test.dto.PersonDTO;
+import org.eclipsefoundation.persistence.test.model.PersonModel;
+import org.mapstruct.InheritInverseConfiguration;
+import org.mapstruct.Mapper;
+
+/**
+ * A Mapper used for testing. It maps between 2 test entity classes,
+ * PersonDTO and PersonModel.
+ */
+@Mapper(config = QuarkusMappingConfig.class)
+public interface PersonMapper extends EntityMapper {
+
+ PersonModel toModel(PersonDTO personDTO);
+
+ @InheritInverseConfiguration
+ PersonDTO toDTO(PersonModel personModel);
+
+ @Override
+ default Class getDTOType() {
+ return PersonDTO.class;
+ }
+
+ @Override
+ default Class getModelType() {
+ return PersonModel.class;
+ }
+}
\ No newline at end of file
diff --git a/persistence/runtime/src/test/java/org/eclipsefoundation/persistence/test/dto/PersonDTO.java b/persistence/runtime/src/test/java/org/eclipsefoundation/persistence/test/dto/PersonDTO.java
new file mode 100644
index 0000000000000000000000000000000000000000..b6204093dac233c166e579d45ced355a9a35bc59
--- /dev/null
+++ b/persistence/runtime/src/test/java/org/eclipsefoundation/persistence/test/dto/PersonDTO.java
@@ -0,0 +1,58 @@
+/*********************************************************************
+* Copyright (c) 2022 Eclipse Foundation
+*
+* This program and the accompanying materials are made
+* available under the terms of the Eclipse Public License 2.0
+* which is available at https://www.eclipse.org/legal/epl-2.0/
+*
+* SPDX-License-Identifier: EPL-2.0
+**********************************************************************/
+package org.eclipsefoundation.persistence.test.dto;
+
+import java.io.Serializable;
+
+import javax.persistence.Column;
+import javax.persistence.Id;
+
+import org.eclipsefoundation.persistence.dto.BareNode;
+
+/**
+ * A basic DTO class with a few simple fields. Used for testing.
+ */
+public class PersonDTO extends BareNode implements Serializable {
+
+ @Id
+ @Column(unique = true, nullable = false)
+ private String personID;
+ private String name;
+ private int age;
+
+ @Override
+ public Object getId() {
+ return getPersonID();
+ }
+
+ public String getPersonID() {
+ return this.personID;
+ }
+
+ public void setPersonID(String id) {
+ this.personID = id;
+ }
+
+ public String getName() {
+ return this.name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public int getAge() {
+ return this.age;
+ }
+
+ public void setAge(int age) {
+ this.age = age;
+ }
+}
\ No newline at end of file
diff --git a/persistence/runtime/src/test/java/org/eclipsefoundation/persistence/test/model/PersonModel.java b/persistence/runtime/src/test/java/org/eclipsefoundation/persistence/test/model/PersonModel.java
new file mode 100644
index 0000000000000000000000000000000000000000..7023d37e0546e0d368db810a9d3b8075d545bd99
--- /dev/null
+++ b/persistence/runtime/src/test/java/org/eclipsefoundation/persistence/test/model/PersonModel.java
@@ -0,0 +1,43 @@
+/*******************************************************************************
+ * Copyright (C) 2022 Eclipse Foundation
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ ******************************************************************************/
+package org.eclipsefoundation.persistence.test.model;
+
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder;
+import com.google.auto.value.AutoValue;
+
+/**
+ * A basic Model class with a few simple fields. Used for testing.
+ */
+@AutoValue
+@JsonDeserialize(builder = AutoValue_PersonModel.Builder.class)
+public abstract class PersonModel {
+ public abstract String getPersonID();
+
+ public abstract String getName();
+
+ public abstract int getAge();
+
+ public static Builder builder() {
+ return new AutoValue_PersonModel.Builder();
+ }
+
+ @AutoValue.Builder
+ @JsonPOJOBuilder(withPrefix = "set")
+ public abstract static class Builder {
+ public abstract Builder setPersonID(String personID);
+
+ public abstract Builder setName(String name);
+
+ public abstract Builder setAge(int age);
+
+ public abstract PersonModel build();
+ }
+}
\ No newline at end of file