From 51044735a8fdb11ee1df36fa33334d317e1e94ee Mon Sep 17 00:00:00 2001 From: Matija Obreza Date: Wed, 8 Jun 2016 12:39:30 +0200 Subject: [PATCH] Crop otherNames is lazy-loaded --- .../org/genesys2/server/model/impl/Crop.java | 8 +-- .../server/service/impl/CropServiceImpl.java | 20 ++++--- .../tests/resttests/ApiDocumentation.java | 47 +++++++--------- .../tests/resttests/CropsControllerTest.java | 53 ++++++++----------- 4 files changed, 60 insertions(+), 68 deletions(-) diff --git a/src/main/java/org/genesys2/server/model/impl/Crop.java b/src/main/java/org/genesys2/server/model/impl/Crop.java index 543813343..7844fc3ce 100644 --- a/src/main/java/org/genesys2/server/model/impl/Crop.java +++ b/src/main/java/org/genesys2/server/model/impl/Crop.java @@ -25,6 +25,7 @@ import java.util.Locale; import java.util.Map; import javax.persistence.Cacheable; +import javax.persistence.CascadeType; import javax.persistence.CollectionTable; import javax.persistence.Column; import javax.persistence.ElementCollection; @@ -65,8 +66,7 @@ public class Crop extends GlobalVersionedAuditedModel implements AclAwareModel { private String shortName; @Column(name = "otherName", nullable = false) - //FetchType.LAZY doesn't work in unit tests, it causes org.hibernate.LazyInitializationException - @ElementCollection(fetch = FetchType.EAGER) + @ElementCollection(fetch = FetchType.LAZY) @CollectionTable(name = "cropname", joinColumns = @JoinColumn(name = "cropId", referencedColumnName = "id"), uniqueConstraints = { @UniqueConstraint(columnNames = "otherName") }) @OrderBy("otherName") private List otherNames; @@ -86,7 +86,7 @@ public class Crop extends GlobalVersionedAuditedModel implements AclAwareModel { * Rules */ @JsonIgnore - @OneToMany(mappedBy = "crop", cascade = {}, orphanRemoval = true) + @OneToMany(mappedBy = "crop", cascade = { CascadeType.REMOVE }, orphanRemoval = true) private List cropRules; @Transient @@ -100,7 +100,7 @@ public class Crop extends GlobalVersionedAuditedModel implements AclAwareModel { @Transient @JsonIgnore private transient JsonNode i18nJU; - + public String getName() { return name; diff --git a/src/main/java/org/genesys2/server/service/impl/CropServiceImpl.java b/src/main/java/org/genesys2/server/service/impl/CropServiceImpl.java index 3dc9f39ed..6e07dea98 100644 --- a/src/main/java/org/genesys2/server/service/impl/CropServiceImpl.java +++ b/src/main/java/org/genesys2/server/service/impl/CropServiceImpl.java @@ -74,17 +74,23 @@ public class CropServiceImpl implements CropService { @Override public Crop getCrop(String shortName) { Crop crop = cropRepository.findByShortName(shortName); + + // Find crop by alias when null if (crop == null) { - // Find crop by alias crop = cropRepository.findByOtherNames(shortName); } + + // Lazy load otherNames + if (crop != null && crop.getOtherNames() != null) + crop.getOtherNames().size(); + return crop; } @PreAuthorize("hasRole('ADMINISTRATOR')") @Override @Transactional - @CacheEvict(allEntries=true, value=CACHE_CROPS) + @CacheEvict(allEntries = true, value = CACHE_CROPS) public Crop delete(Crop crop) { cropRepository.delete(crop); crop.setId(null); @@ -104,7 +110,8 @@ public class CropServiceImpl implements CropService { List crops = cropRepository.findAll(); // Fetch otherNames list crops.stream().forEach(c -> { - c.getOtherNames().size(); + if (c.getOtherNames() != null) + c.getOtherNames().size(); }); return crops; } @@ -115,7 +122,8 @@ public class CropServiceImpl implements CropService { final List crops = cropRepository.findAll(); // Fetch otherNames list crops.stream().forEach(c -> { - c.getOtherNames().size(); + if (c.getOtherNames() != null) + c.getOtherNames().size(); }); Collections.sort(crops, new Comparator() { @Override @@ -260,7 +268,7 @@ public class CropServiceImpl implements CropService { @Override @PreAuthorize("hasRole('ADMINISTRATOR')") @Transactional(readOnly = false) - @CacheEvict(allEntries=true, value=CACHE_CROPS) + @CacheEvict(allEntries = true, value = CACHE_CROPS) public Crop addCrop(String shortName, String name, String description, String i18n) { LOG.info("Adding crop " + shortName); final Crop crop = new Crop(); @@ -281,7 +289,7 @@ public class CropServiceImpl implements CropService { @Override @PreAuthorize("hasRole('ADMINISTRATOR') or hasPermission(#crop, 'ADMINISTRATION')") @Transactional(readOnly = false) - @CacheEvict(allEntries=true, value=CACHE_CROPS) + @CacheEvict(allEntries = true, value = CACHE_CROPS) public Crop updateCrop(Crop crop, String name, String description, String i18n) { LOG.info("Updating crop " + crop); diff --git a/src/test/java/org/genesys2/tests/resttests/ApiDocumentation.java b/src/test/java/org/genesys2/tests/resttests/ApiDocumentation.java index afabeebfa..a69157e4f 100644 --- a/src/test/java/org/genesys2/tests/resttests/ApiDocumentation.java +++ b/src/test/java/org/genesys2/tests/resttests/ApiDocumentation.java @@ -1,23 +1,11 @@ package org.genesys2.tests.resttests; -import static org.hamcrest.Matchers.hasSize; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.notNullValue; -import static org.hamcrest.Matchers.nullValue; -import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; -import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.documentationConfiguration; -import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.delete; -import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get; -import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.post; -import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.put; -import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath; -import static org.springframework.restdocs.payload.PayloadDocumentation.requestFields; -import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields; -import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName; -import static org.springframework.restdocs.request.RequestDocumentation.pathParameters; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static org.hamcrest.Matchers.*; +import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.*; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.*; +import static org.springframework.restdocs.payload.PayloadDocumentation.*; +import static org.springframework.restdocs.request.RequestDocumentation.*; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; import java.util.ArrayList; import java.util.List; @@ -46,6 +34,7 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; +@Transactional(transactionManager = "transactionManager") public class ApiDocumentation extends AbstractRestTest { private static final Log LOG = LogFactory.getLog(ApiDocumentation.class); @@ -115,27 +104,27 @@ public class ApiDocumentation extends AbstractRestTest { public void createCropTest() throws Exception { LOG.info("Start test-method createCropTest"); - cropRepository.deleteAll(); - mockMvc.perform(post("/api/v0/crops") .contentType(MediaType.APPLICATION_JSON) .content(objectMapper.writeValueAsString(new Object() { - public String shortName="maize"; - public String name="Maize"; + public String shortName="rice"; + public String name="Rice"; public String description="Crop description in EN"; + public String[] otherNames = { "ris", "riž" }; }))) .andExpect(status().isOk()) .andExpect(content().contentType(MediaType.APPLICATION_JSON)) .andExpect(jsonPath("$.id", is(notNullValue()))) .andExpect(jsonPath("$.version", is(0))) - .andExpect(jsonPath("$.shortName", is("maize"))) + .andExpect(jsonPath("$.shortName", is("rice"))) .andExpect(jsonPath("$.i18n", is(nullValue()))) - .andExpect(jsonPath("$.name", is("Maize"))) + .andExpect(jsonPath("$.name", is("Rice"))) .andExpect(jsonPath("$.description", is("Crop description in EN"))) .andDo(document("crop-create", requestFields( fieldWithPath("shortName").description("Crop short name or code (e.g. maize)"), fieldWithPath("name").description("Crop name in English"), + fieldWithPath("otherNames").type(JsonFieldType.ARRAY).optional().description("Alternative spellings of the crop name"), fieldWithPath("description").optional().description("Crop description in English") ), responseFields( @@ -145,6 +134,7 @@ public class ApiDocumentation extends AbstractRestTest { fieldWithPath("shortName").description("Crop short name or code (e.g. maize)"), fieldWithPath("description").description("Crop description in English"), fieldWithPath("rdfUri").type(JsonFieldType.STRING).optional().description("URI of RDF term describing the crop"), + fieldWithPath("otherNames").type(JsonFieldType.ARRAY).optional().description("Alternative spellings of the crop name"), fieldWithPath("i18n").type(JsonFieldType.STRING).optional().description("i18n map"), fieldWithPath("createdBy").ignored(), fieldWithPath("createdDate").ignored(), @@ -177,6 +167,7 @@ public class ApiDocumentation extends AbstractRestTest { fieldWithPath("name").description("Crop name in English"), fieldWithPath("shortName").description("Crop short name or code (e.g. maize)"), fieldWithPath("description").description("Crop description in English"), + fieldWithPath("otherNames").type(JsonFieldType.ARRAY).optional().description("Alternative spellings of the crop name"), fieldWithPath("rdfUri").type(JsonFieldType.STRING).optional().description("URI of RDF term describing the crop"), fieldWithPath("i18n").type(JsonFieldType.STRING).optional().description("i18n map"), fieldWithPath("createdBy").ignored(), @@ -191,16 +182,18 @@ public class ApiDocumentation extends AbstractRestTest { @Test public void deleteCropTest() throws Exception { LOG.info("Start test-method deleteCropTest"); + + createCropTest(); - mockMvc.perform(delete("/api/v0/crops/{shortName}", crop.getShortName()) + mockMvc.perform(delete("/api/v0/crops/{shortName}", "rice") .contentType(MediaType.APPLICATION_JSON)) .andExpect(status().isOk()) .andExpect(content().contentType(MediaType.APPLICATION_JSON)) .andExpect(jsonPath("$.id", is(nullValue()))) .andExpect(jsonPath("$.version", is(0))) - .andExpect(jsonPath("$.shortName", is("maize"))) + .andExpect(jsonPath("$.shortName", is("rice"))) .andExpect(jsonPath("$.i18n", is(nullValue()))) - .andExpect(jsonPath("$.name", is("Maize"))) + .andExpect(jsonPath("$.name", is("Rice"))) .andExpect(jsonPath("$.description", is("Crop description in EN"))) .andDo(document("crop-delete", pathParameters( parameterWithName("shortName").description("Crop short name or code (e.g. maize)") diff --git a/src/test/java/org/genesys2/tests/resttests/CropsControllerTest.java b/src/test/java/org/genesys2/tests/resttests/CropsControllerTest.java index 390c78692..4ec1f2007 100644 --- a/src/test/java/org/genesys2/tests/resttests/CropsControllerTest.java +++ b/src/test/java/org/genesys2/tests/resttests/CropsControllerTest.java @@ -1,23 +1,11 @@ package org.genesys2.tests.resttests; -import static org.hamcrest.Matchers.hasSize; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.notNullValue; -import static org.hamcrest.Matchers.nullValue; -import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; -import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.documentationConfiguration; -import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.delete; -import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get; -import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.post; -import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.put; -import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath; -import static org.springframework.restdocs.payload.PayloadDocumentation.requestFields; -import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields; -import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName; -import static org.springframework.restdocs.request.RequestDocumentation.pathParameters; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static org.hamcrest.Matchers.*; +import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.*; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.*; +import static org.springframework.restdocs.payload.PayloadDocumentation.*; +import static org.springframework.restdocs.request.RequestDocumentation.*; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; import java.util.ArrayList; import java.util.List; @@ -35,6 +23,8 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.MediaType; import org.springframework.restdocs.RestDocumentation; import org.springframework.restdocs.payload.JsonFieldType; +import org.springframework.test.annotation.Commit; +import org.springframework.test.annotation.Rollback; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.setup.MockMvcBuilders; import org.springframework.transaction.annotation.Transactional; @@ -46,6 +36,7 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; +@Transactional(transactionManager = "transactionManager") public class CropsControllerTest extends AbstractRestTest { private static final Log LOG = LogFactory.getLog(CropsControllerTest.class); @@ -78,7 +69,6 @@ public class CropsControllerTest extends AbstractRestTest { .withPort(443)).build(); crop = cropService.addCrop("maize", "Maize", "Crop description in EN", null); - cropRule = cropService.addCropRule(crop, "Zea", "mays", true); List cropRules = new ArrayList<>(); @@ -88,7 +78,8 @@ public class CropsControllerTest extends AbstractRestTest { @After public void tearDown() { - cropRepository.deleteAll(); + cropRuleRepository.delete(cropRule); + cropRepository.delete(crop); } @Test @@ -115,22 +106,20 @@ public class CropsControllerTest extends AbstractRestTest { public void createCropTest() throws Exception { LOG.info("Start test-method createCropTest"); - cropRepository.deleteAll(); - mockMvc.perform(post("/api/v0/crops") .contentType(MediaType.APPLICATION_JSON) .content(objectMapper.writeValueAsString(new Object() { - public String shortName="maize"; - public String name="Maize"; + public String shortName="rice"; + public String name="Rice"; public String description="Crop description in EN"; }))) .andExpect(status().isOk()) .andExpect(content().contentType(MediaType.APPLICATION_JSON)) .andExpect(jsonPath("$.id", is(notNullValue()))) .andExpect(jsonPath("$.version", is(0))) - .andExpect(jsonPath("$.shortName", is("maize"))) + .andExpect(jsonPath("$.shortName", is("rice"))) .andExpect(jsonPath("$.i18n", is(nullValue()))) - .andExpect(jsonPath("$.name", is("Maize"))) + .andExpect(jsonPath("$.name", is("Rice"))) .andExpect(jsonPath("$.description", is("Crop description in EN"))) .andDo(document("crop-create", requestFields( @@ -146,7 +135,7 @@ public class CropsControllerTest extends AbstractRestTest { fieldWithPath("description").description("Crop description in English"), fieldWithPath("rdfUri").type(JsonFieldType.STRING).optional().description("URI of RDF term describing the crop"), fieldWithPath("i18n").type(JsonFieldType.STRING).optional().description("i18n map"), - fieldWithPath("otherNames").ignored(), + fieldWithPath("otherNames").type(JsonFieldType.ARRAY).optional().description("Alternative spellings of the crop name"), fieldWithPath("createdBy").ignored(), fieldWithPath("createdDate").ignored(), fieldWithPath("lastModifiedBy").ignored(), @@ -180,7 +169,7 @@ public class CropsControllerTest extends AbstractRestTest { fieldWithPath("description").description("Crop description in English"), fieldWithPath("rdfUri").type(JsonFieldType.STRING).optional().description("URI of RDF term describing the crop"), fieldWithPath("i18n").type(JsonFieldType.STRING).optional().description("i18n map"), - fieldWithPath("otherNames").ignored(), + fieldWithPath("otherNames").type(JsonFieldType.ARRAY).optional().description("Alternative spellings of the crop name"), fieldWithPath("createdBy").ignored(), fieldWithPath("createdDate").ignored(), fieldWithPath("lastModifiedBy").ignored(), @@ -194,15 +183,17 @@ public class CropsControllerTest extends AbstractRestTest { public void deleteCropTest() throws Exception { LOG.info("Start test-method deleteCropTest"); - mockMvc.perform(delete("/api/v0/crops/{shortName}", crop.getShortName()) + createCropTest(); + + mockMvc.perform(delete("/api/v0/crops/{shortName}", "rice") .contentType(MediaType.APPLICATION_JSON)) .andExpect(status().isOk()) .andExpect(content().contentType(MediaType.APPLICATION_JSON)) .andExpect(jsonPath("$.id", is(nullValue()))) .andExpect(jsonPath("$.version", is(0))) - .andExpect(jsonPath("$.shortName", is("maize"))) + .andExpect(jsonPath("$.shortName", is("rice"))) .andExpect(jsonPath("$.i18n", is(nullValue()))) - .andExpect(jsonPath("$.name", is("Maize"))) + .andExpect(jsonPath("$.name", is("Rice"))) .andExpect(jsonPath("$.description", is("Crop description in EN"))) .andDo(document("crop-delete", pathParameters( parameterWithName("shortName").description("Crop short name or code (e.g. maize)") -- GitLab