Deliver HgConfigPackages no longer as embedded.

They don't have an own identity in terms of REST and its much simpler
to return a simple list instead of an _embedded list.
Also gets rid of one HgConfigPackageToDtoMapper.
This commit is contained in:
Johannes Schnatterer
2018-08-07 16:47:03 +02:00
parent adde70f090
commit 45822c44cb
12 changed files with 118 additions and 150 deletions

View File

@@ -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<String> paths;
public HgConfigInstallationsDto(Links links, List<String> paths) {
super(links);
this.paths = paths;
}
private List<String> paths;
}

View File

@@ -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;
}

View File

@@ -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<HgPackage, HgConfigPackageDto> {
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();
}
}

View File

@@ -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;
}

View File

@@ -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<HgPackage, HgConfigPackageDto> {
@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
}

View File

@@ -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<HgConfigPackageDto> 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;
}
}

View File

@@ -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<HgPackage> packages;
HgPackagesNonIterable(HgPackages hgPackages) {
this.packages = hgPackages.getPackages();
}
}
}

View File

@@ -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

View File

@@ -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);

View File

@@ -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);
}
}

View File

@@ -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<HgPackage> hgPackages = createPackages();
HgPackages hgPackages = new HgPackages();
hgPackages.setPackages(createPackages());
HalRepresentation dto = mapper.map(hgPackages);
HgConfigPackagesDto dto = mapper.map(hgPackages);
List<HalRepresentation> 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<HgPackage> createPackages() {
private List<HgPackage> createPackages() {
return Arrays.asList(createPackage(), new HgPackage());
}

View File

@@ -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());
}
}