diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/api/v2/resources/HgConfigInstallationsDto.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/api/v2/resources/HgConfigInstallationsDto.java index be97e2972b..b60f7f5460 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/api/v2/resources/HgConfigInstallationsDto.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/api/v2/resources/HgConfigInstallationsDto.java @@ -3,20 +3,19 @@ package sonia.scm.api.v2.resources; import de.otto.edison.hal.HalRepresentation; import de.otto.edison.hal.Links; import lombok.Getter; -import lombok.NoArgsConstructor; import lombok.Setter; import java.util.List; -@NoArgsConstructor @Getter @Setter public class HgConfigInstallationsDto extends HalRepresentation { + private List paths; + public HgConfigInstallationsDto(Links links, List paths) { super(links); this.paths = paths; } - private List paths; } diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/api/v2/resources/HgConfigInstallationsToDtoMapper.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/api/v2/resources/HgConfigInstallationsToDtoMapper.java index 575166c007..d2f4aecf7e 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/api/v2/resources/HgConfigInstallationsToDtoMapper.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/api/v2/resources/HgConfigInstallationsToDtoMapper.java @@ -1,7 +1,7 @@ package sonia.scm.api.v2.resources; -import com.google.inject.Inject; +import javax.inject.Inject; import java.util.List; import static de.otto.edison.hal.Links.linkingTo; @@ -11,7 +11,7 @@ public class HgConfigInstallationsToDtoMapper { private UriInfoStore uriInfoStore; @Inject - public HgConfigInstallationsToDtoMapper(UriInfoStore uriInfoStore, String path) { + public HgConfigInstallationsToDtoMapper(UriInfoStore uriInfoStore) { this.uriInfoStore = uriInfoStore; } diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/api/v2/resources/HgConfigPackageCollectionToDtoMapper.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/api/v2/resources/HgConfigPackageCollectionToDtoMapper.java deleted file mode 100644 index 46f4526aa4..0000000000 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/api/v2/resources/HgConfigPackageCollectionToDtoMapper.java +++ /dev/null @@ -1,25 +0,0 @@ -package sonia.scm.api.v2.resources; - -import sonia.scm.installer.HgPackage; - -import javax.inject.Inject; - -// TODO could this be simplified similar to HgConfigInstallationsToDtoMapper? -// That is, do we really need the packages as _embedded list? -public class HgConfigPackageCollectionToDtoMapper extends CollectionToDtoMapper { - - static final String COLLECTION_NAME = "packages"; - private UriInfoStore uriInfoStore; - - @Inject - public HgConfigPackageCollectionToDtoMapper(HgConfigPackageToDtoMapper mapper, UriInfoStore uriInfoStore) { - super(COLLECTION_NAME, mapper); - this.uriInfoStore = uriInfoStore; - } - - @Override - protected String createSelfLink() { - LinkBuilder linkBuilder = new LinkBuilder(uriInfoStore.get(), HgConfigResource.class); - return linkBuilder.method("getPackagesResource").parameters().href(); - } -} diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/api/v2/resources/HgConfigPackageDto.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/api/v2/resources/HgConfigPackageDto.java deleted file mode 100644 index 8e22d1026d..0000000000 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/api/v2/resources/HgConfigPackageDto.java +++ /dev/null @@ -1,21 +0,0 @@ -package sonia.scm.api.v2.resources; - -import de.otto.edison.hal.HalRepresentation; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; - -@NoArgsConstructor -@Getter -@Setter -public class HgConfigPackageDto extends HalRepresentation { - - private String arch; - private HgConfigDto hgConfigTemplate; - private String hgVersion; - private String id; - private String platform; - private String pythonVersion; - private long size; - private String url; -} diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/api/v2/resources/HgConfigPackageToDtoMapper.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/api/v2/resources/HgConfigPackageToDtoMapper.java deleted file mode 100644 index 31671e3e14..0000000000 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/api/v2/resources/HgConfigPackageToDtoMapper.java +++ /dev/null @@ -1,20 +0,0 @@ -package sonia.scm.api.v2.resources; - -import org.mapstruct.Mapper; -import org.mapstruct.Mapping; -import sonia.scm.installer.HgPackage; - -import javax.inject.Inject; - -@Mapper -public abstract class HgConfigPackageToDtoMapper extends BaseMapper { - @Inject - private UriInfoStore uriInfoStore; - - @Override - @Mapping(target = "attributes", ignore = true) // We do not map HAL attributes - @Mapping(target = "hgConfigTemplate.attributes", ignore = true) // Also not for nested DTOs - public abstract HgConfigPackageDto map(HgPackage modelObject); - - // Don't add links because ConfigPackages don't have their own ressource -} diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/api/v2/resources/HgConfigPackagesDto.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/api/v2/resources/HgConfigPackagesDto.java new file mode 100644 index 0000000000..959df12b61 --- /dev/null +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/api/v2/resources/HgConfigPackagesDto.java @@ -0,0 +1,38 @@ +package sonia.scm.api.v2.resources; + +import de.otto.edison.hal.HalRepresentation; +import de.otto.edison.hal.Links; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import java.util.List; + +@NoArgsConstructor +@Getter +@Setter +public class HgConfigPackagesDto extends HalRepresentation { + + private List packages; + + @Override + @SuppressWarnings("squid:S1185") // We want to have this method available in this package + protected HalRepresentation add(Links links) { + return super.add(links); + } + + @NoArgsConstructor + @Getter + @Setter + public static class HgConfigPackageDto { + + private String arch; + private HgConfigDto hgConfigTemplate; + private String hgVersion; + private String id; + private String platform; + private String pythonVersion; + private long size; + private String url; + } +} diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/api/v2/resources/HgConfigPackagesToDtoMapper.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/api/v2/resources/HgConfigPackagesToDtoMapper.java new file mode 100644 index 0000000000..67d7e58dff --- /dev/null +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/api/v2/resources/HgConfigPackagesToDtoMapper.java @@ -0,0 +1,59 @@ +package sonia.scm.api.v2.resources; + +import de.otto.edison.hal.Links; +import lombok.Getter; +import org.mapstruct.AfterMapping; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.MappingTarget; +import sonia.scm.installer.HgPackage; +import sonia.scm.installer.HgPackages; + +import javax.inject.Inject; +import java.util.List; + +import static de.otto.edison.hal.Links.linkingTo; + +// Mapstruct does not support parameterized (i.e. non-default) constructors. Thus, we need to use field injection. +@SuppressWarnings("squid:S3306") +@Mapper +public abstract class HgConfigPackagesToDtoMapper { + + @Inject + private UriInfoStore uriInfoStore; + + public HgConfigPackagesDto map(HgPackages hgpackages) { + return map(new HgPackagesNonIterable(hgpackages)); + } + + @Mapping(target = "attributes", ignore = true) // We do not map HAL attributes + /* Favor warning "Unmapped target property: "attributes", to packages[].hgConfigTemplate" + Over error "Unknown property "packages[].hgConfigTemplate.attributes" + @Mapping(target = "packages[].hgConfigTemplate.attributes", ignore = true) // Also not for nested DTOs + */ + protected abstract HgConfigPackagesDto map(HgPackagesNonIterable hgPackagesNonIterable); + + @AfterMapping + void appendLinks(@MappingTarget HgConfigPackagesDto target) { + Links.Builder linksBuilder = linkingTo().self(createSelfLink()); + target.add(linksBuilder.build()); + } + + private String createSelfLink() { + LinkBuilder linkBuilder = new LinkBuilder(uriInfoStore.get(), HgConfigResource.class); + return linkBuilder.method("getPackagesResource").parameters().href(); + } + + /** + * Unfortunately, HgPackages is iterable, HgConfigPackagesDto does not need to be iterable and MapStruct refuses to + * map an iterable to a non-iterable. So use this little non-iterable "proxy". + */ + @Getter + static class HgPackagesNonIterable { + private List packages; + + HgPackagesNonIterable(HgPackages hgPackages) { + this.packages = hgPackages.getPackages(); + } + } +} diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgServletModule.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgServletModule.java index dd1fbd4748..357995483d 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgServletModule.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgServletModule.java @@ -39,8 +39,7 @@ import com.google.inject.servlet.ServletModule; import org.mapstruct.factory.Mappers; import sonia.scm.api.v2.resources.HgConfigDtoToHgConfigMapper; import sonia.scm.api.v2.resources.HgConfigInstallationsToDtoMapper; -import sonia.scm.api.v2.resources.HgConfigPackageCollectionToDtoMapper; -import sonia.scm.api.v2.resources.HgConfigPackageToDtoMapper; +import sonia.scm.api.v2.resources.HgConfigPackagesToDtoMapper; import sonia.scm.api.v2.resources.HgConfigToHgConfigDtoMapper; import sonia.scm.installer.HgPackageReader; import sonia.scm.plugin.Extension; @@ -77,8 +76,7 @@ public class HgServletModule extends ServletModule bind(HgConfigDtoToHgConfigMapper.class).to(Mappers.getMapper(HgConfigDtoToHgConfigMapper.class).getClass()); bind(HgConfigToHgConfigDtoMapper.class).to(Mappers.getMapper(HgConfigToHgConfigDtoMapper.class).getClass()); - bind(HgConfigPackageToDtoMapper.class).to(Mappers.getMapper(HgConfigPackageToDtoMapper.class).getClass()); - bind(HgConfigPackageCollectionToDtoMapper.class); + bind(HgConfigPackagesToDtoMapper.class).to(Mappers.getMapper(HgConfigPackagesToDtoMapper.class).getClass()); bind(HgConfigInstallationsToDtoMapper.class); // bind servlets diff --git a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/api/v2/resources/HgConfigPackageResourceTest.java b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/api/v2/resources/HgConfigPackageResourceTest.java index e91662df3f..a2ae6739eb 100644 --- a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/api/v2/resources/HgConfigPackageResourceTest.java +++ b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/api/v2/resources/HgConfigPackageResourceTest.java @@ -56,12 +56,12 @@ public class HgConfigPackageResourceTest { private final URI baseUri = java.net.URI.create("/"); - @InjectMocks - private HgConfigPackageToDtoMapperImpl hgConfigPackageToDtoMapper; - @Mock(answer = Answers.RETURNS_DEEP_STUBS) private UriInfoStore uriInfoStore; + @InjectMocks + private HgConfigPackagesToDtoMapperImpl mapper; + @Mock private HgRepositoryHandler repositoryHandler; @@ -96,11 +96,7 @@ public class HgConfigPackageResourceTest { String responseString = response.getContentAsString(); ObjectNode responseJson = new ObjectMapper().readValue(responseString, ObjectNode.class); - - JsonNode embedded = responseJson.get("_embedded"); - assertThat(embedded).isNotNull(); - - JsonNode packages = embedded.get("packages"); + JsonNode packages = responseJson.get("packages"); assertThat(packages).isNotNull(); assertThat(packages).hasSize(2); @@ -191,9 +187,6 @@ public class HgConfigPackageResourceTest { } private void setupResources() { - HgConfigPackageCollectionToDtoMapper mapper = - new HgConfigPackageCollectionToDtoMapper(hgConfigPackageToDtoMapper, uriInfoStore); - HgConfigPackageResource hgConfigPackageResource = new HgConfigPackageResource(hgPackageReader, advancedHttpClient, repositoryHandler, mapper); diff --git a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/api/v2/resources/HgConfigPackageToDtoMapperTest.java b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/api/v2/resources/HgConfigPackageToDtoMapperTest.java deleted file mode 100644 index 205096460a..0000000000 --- a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/api/v2/resources/HgConfigPackageToDtoMapperTest.java +++ /dev/null @@ -1,43 +0,0 @@ -package sonia.scm.api.v2.resources; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Answers; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.runners.MockitoJUnitRunner; -import sonia.scm.installer.HgPackage; - -import java.net.URI; - -import static org.mockito.Mockito.when; -import static sonia.scm.api.v2.resources.HgConfigTests.assertEqualsPackage; -import static sonia.scm.api.v2.resources.HgConfigTests.createPackage; - -@RunWith(MockitoJUnitRunner.class) -public class HgConfigPackageToDtoMapperTest { - - private URI baseUri = URI.create("http://example.com/base/"); - - @Mock(answer = Answers.RETURNS_DEEP_STUBS) - private UriInfoStore uriInfoStore; - - @InjectMocks - private HgConfigPackageToDtoMapperImpl mapper; - - @Before - public void init() { - when(uriInfoStore.get().getBaseUri()).thenReturn(baseUri); - } - - @Test - public void shouldMapFields() { - HgPackage hgPackage = createPackage(); - - HgConfigPackageDto dto = mapper.map(hgPackage); - - assertEqualsPackage(dto); - } - -} diff --git a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/api/v2/resources/HgConfigPackageCollectionToDtoMapperTest.java b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/api/v2/resources/HgConfigPackagesToDtoMapperTest.java similarity index 58% rename from scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/api/v2/resources/HgConfigPackageCollectionToDtoMapperTest.java rename to scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/api/v2/resources/HgConfigPackagesToDtoMapperTest.java index 27cd3c73c3..671d9fb7e1 100644 --- a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/api/v2/resources/HgConfigPackageCollectionToDtoMapperTest.java +++ b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/api/v2/resources/HgConfigPackagesToDtoMapperTest.java @@ -9,6 +9,7 @@ import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; import sonia.scm.installer.HgPackage; +import sonia.scm.installer.HgPackages; import java.net.URI; import java.util.Arrays; @@ -19,12 +20,11 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.when; -import static sonia.scm.api.v2.resources.HgConfigPackageCollectionToDtoMapper.COLLECTION_NAME; import static sonia.scm.api.v2.resources.HgConfigTests.assertEqualsPackage; import static sonia.scm.api.v2.resources.HgConfigTests.createPackage; @RunWith(MockitoJUnitRunner.class) -public class HgConfigPackageCollectionToDtoMapperTest { +public class HgConfigPackagesToDtoMapperTest { private URI baseUri = URI.create("http://example.com/base/"); @@ -32,9 +32,7 @@ public class HgConfigPackageCollectionToDtoMapperTest { private UriInfoStore uriInfoStore; @InjectMocks - private HgConfigPackageToDtoMapperImpl hgConfigPackageToDtoMapper; - - private HgConfigPackageCollectionToDtoMapper mapper; + private HgConfigPackagesToDtoMapperImpl mapper; private URI expectedBaseUri; @@ -42,35 +40,29 @@ public class HgConfigPackageCollectionToDtoMapperTest { public void init() { when(uriInfoStore.get().getBaseUri()).thenReturn(baseUri); expectedBaseUri = baseUri.resolve(HgConfigResource.HG_CONFIG_PATH_V2 + "/packages"); - mapper = new HgConfigPackageCollectionToDtoMapper(hgConfigPackageToDtoMapper, uriInfoStore); } @Test public void shouldMapFields() { - Collection hgPackages = createPackages(); + HgPackages hgPackages = new HgPackages(); + hgPackages.setPackages(createPackages()); - HalRepresentation dto = mapper.map(hgPackages); + HgConfigPackagesDto dto = mapper.map(hgPackages); - List itemsBy = dto.getEmbedded().getItemsBy(COLLECTION_NAME); - assertThat(itemsBy).hasSize(2); + assertThat(dto.getPackages()).hasSize(2); - HgConfigPackageDto hgPackageDto1 = assertAndGetAsDto(itemsBy.get(0)); + HgConfigPackagesDto.HgConfigPackageDto hgPackageDto1 = dto.getPackages().get(0); assertEqualsPackage(hgPackageDto1); - HgConfigPackageDto hgPackageDto2 = assertAndGetAsDto(itemsBy.get(1)); - assertTrue(hgPackageDto2.getLinks().isEmpty()); + HgConfigPackagesDto.HgConfigPackageDto hgPackageDto2 = dto.getPackages().get(1); // Just verify a random field assertThat(hgPackageDto2.getId()).isNull(); assertEquals(expectedBaseUri.toString(), dto.getLinks().getLinkBy("self").get().getHref()); } - private HgConfigPackageDto assertAndGetAsDto(HalRepresentation halRepresentation) { - assertThat(halRepresentation).isInstanceOf(HgConfigPackageDto.class); - return (HgConfigPackageDto) halRepresentation; - } - private Collection createPackages() { + private List createPackages() { return Arrays.asList(createPackage(), new HgPackage()); } diff --git a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/api/v2/resources/HgConfigTests.java b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/api/v2/resources/HgConfigTests.java index 4022d35f1c..4167321344 100644 --- a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/api/v2/resources/HgConfigTests.java +++ b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/api/v2/resources/HgConfigTests.java @@ -53,7 +53,7 @@ class HgConfigTests { return hgPackage; } - static void assertEqualsPackage(HgConfigPackageDto dto) { + static void assertEqualsPackage(HgConfigPackagesDto.HgConfigPackageDto dto) { assertEquals("arch", dto.getArch()); assertEquals("1", dto.getId()); assertEquals("2", dto.getHgVersion()); @@ -64,8 +64,6 @@ class HgConfigTests { assertEqualsConfiguration(dto.getHgConfigTemplate()); assertTrue(dto.getHgConfigTemplate().getLinks().isEmpty()); - - assertTrue(dto.getLinks().isEmpty()); } }