1
我正在試驗新的Spring Security測試框架。我有一個測試,涉及返回一個JPA實體與懶惰的集合。Spring集成測試問題涉及一個懶惰集合的實體
由於其中一個懶惰集合,下列測試最終出錯。
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ActiveProfiles({ Profiles.TEST })
@ContextConfiguration(classes = { FullSecurityTestConfiguration.class, FullIntegrationTestConfiguration.class, BaseTestConfiguration.class, WebMvcConfiguration.class,
EnableHelperComponents.class })
@TestExecutionListeners(listeners = { ServletTestExecutionListener.class, DependencyInjectionTestExecutionListener.class, DirtiesContextTestExecutionListener.class,
TransactionalTestExecutionListener.class, WithSecurityContextTestExcecutionListener.class })
public class CurriculumPermissionEvaluatorAuthorizationTest {
@Autowired
private WebApplicationContext wac;
private MockMvc mockMvc;
@Before
public void setup() {
mockMvc = MockMvcBuilders.webAppContextSetup(wac).build();
}
@After
public void clean() {
SecurityContextHolder.clearContext();
}
@Test
@WithUserDetails("[email protected]")
public void shouldAllowCurriculumRetrieval() throws Exception {
mockMvc.perform(get("/curriculum/findCurriculumById").param("id", "1")//
.contentType(MediaType.APPLICATION_JSON)//
.header("X-Ajax", "true"))//
.andDo(print())//
.andExpect(status().isOk());//
}
以下是錯誤消息:
21:40:52.731 [main] DEBUG o.s.orm.jpa.JpaTransactionManager - Initiating transaction commit
21:40:52.732 [main] DEBUG o.s.orm.jpa.JpaTransactionManager - Committing JPA transaction on EntityManager [[email protected]]
21:40:52.733 [main] DEBUG o.s.orm.jpa.JpaTransactionManager - Closing JPA EntityManager [[email protected]] after transaction
21:40:52.733 [main] DEBUG o.s.o.jpa.EntityManagerFactoryUtils - Closing JPA EntityManager
21:40:52.795 [main] DEBUG o.s.w.s.m.m.a.ResponseBodyAdviceChain - Invoking ResponseBodyAdvice chain for body=Curriculum [drivingLicense=true, smoker=false, maxNumberChildren=2, workExperienceInYears=11, dateOfBirth=1975-01-06 00:00:00.0, telephoneNumber=0142778899, firstName=Juliette, visible=true, validated=true]
21:40:52.796 [main] DEBUG o.s.w.s.m.m.a.ResponseBodyAdviceChain - After ResponseBodyAdvice chain body=Curriculum [drivingLicense=true, smoker=false, maxNumberChildren=2, workExperienceInYears=11, dateOfBirth=1975-01-06 00:00:00.0, telephoneNumber=0142778899, firstName=Juliette, visible=true, validated=true]
21:40:52.819 [main] DEBUG o.s.w.s.m.m.a.ExceptionHandlerExceptionResolver - Resolving exception from handler [public com.bignibou.domain.Curriculum com.bignibou.controller.curriculum.CurriculumController.findCurriculumById(java.lang.Long)]: org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: failed to lazily initialize a collection of role: com.bignibou.domain.Curriculum.workExperiences, could not initialize proxy - no Session (through reference chain: com.bignibou.domain.Curriculum["workExperiences"]); nested exception is com.fasterxml.jackson.databind.JsonMappingException: failed to lazily initialize a collection of role: com.bignibou.domain.Curriculum.workExperiences, could not initialize proxy - no Session (through reference chain: com.bignibou.domain.Curriculum["workExperiences"])
21:40:52.820 [main] DEBUG o.s.w.s.m.a.ResponseStatusExceptionResolver - Resolving exception from handler [public com.bignibou.domain.Curriculum com.bignibou.controller.curriculum.CurriculumController.findCurriculumById(java.lang.Long)]: org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: failed to lazily initialize a collection of role: com.bignibou.domain.Curriculum.workExperiences, could not initialize proxy - no Session (through reference chain: com.bignibou.domain.Curriculum["workExperiences"]); nested exception is com.fasterxml.jackson.databind.JsonMappingException: failed to lazily initialize a collection of role: com.bignibou.domain.Curriculum.workExperiences, could not initialize proxy - no Session (through reference chain: com.bignibou.domain.Curriculum["workExperiences"])
21:40:52.820 [main] DEBUG o.s.w.s.m.s.DefaultHandlerExceptionResolver - Resolving exception from handler [public com.bignibou.domain.Curriculum com.bignibou.controller.curriculum.CurriculumController.findCurriculumById(java.lang.Long)]: org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: failed to lazily initialize a collection of role: com.bignibou.domain.Curriculum.workExperiences, could not initialize proxy - no Session (through reference chain: com.bignibou.domain.Curriculum["workExperiences"]); nested exception is com.fasterxml.jackson.databind.JsonMappingException: failed to lazily initialize a collection of role: com.bignibou.domain.Curriculum.workExperiences, could not initialize proxy - no Session (through reference chain: com.bignibou.domain.Curriculum["workExperiences"])
21:40:52.821 [main] DEBUG o.s.t.w.s.TestDispatcherServlet - Null ModelAndView returned to DispatcherServlet with name '': assuming HandlerAdapter completed request handling
21:40:52.821 [main] DEBUG o.s.t.w.s.TestDispatcherServlet - Successfully completed request
什麼我得到錯誤的,我的測試設置?爲什麼JPA實體經理太早關閉?我怎樣才能繞過這個問題?
編輯1:
從控制器方法:
@Override
@PreAuthorize("isAuthenticated() AND hasPermission(#curriculumId, 'curriculumByIdOwnerPermission')")
@Cacheable(value = CacheConfiguration.DATABASE_CACHE_NAME, key = "'curriculum.Id:' + #curriculumId")
public Curriculum findCurriculum(Long curriculumId) {
return curriculumRepository.findOne(curriculumId);
}
編輯2:
我意識到
@RequestMapping(value = "/findCurriculumById", method = RequestMethod.GET, produces = "application/json")
@ResponseBody
public Curriculum findCurriculumById(@RequestParam Long id) {
return curriculumService.findCurriculum(id);
}
從服務方法測試實際上是錯誤的,即使我已經標註了@Transactional
的測試方法如下:
@Test
@WithUserDetails("[email protected]")
@Transactional
public void shouldAllowCurriculumRetrieval() throws Exception {
mockMvc.perform(get("/curriculum/findCurriculumById").param("id", "1")//
.contentType(MediaType.APPLICATION_JSON)//
.header("X-Ajax", "true"))//
.andDo(print())//
.andExpect(status().isOk());//
}
以下是錯誤消息:
16:54:31.747 [main] DEBUG o.s.s.access.vote.AffirmativeBased - Voter: org.springframewor[email protected]ab4a4ae, returned: 1
16:54:31.747 [main] DEBUG o.s.s.a.i.a.MethodSecurityInterceptor - Authorization successful
16:54:31.747 [main] DEBUG o.s.s.a.i.a.MethodSecurityInterceptor - RunAsManager did not change Authentication object
16:54:31.752 [main] DEBUG o.s.w.s.m.m.a.ResponseBodyAdviceChain - Invoking ResponseBodyAdvice chain for body=Curriculum [drivingLicense=true, smoker=false, maxNumberChildren=2, workExperienceInYears=11, dateOfBirth=1975-01-06 00:00:00.0, telephoneNumber=0142778899, firstName=Juliette, visible=true, validated=true]
16:54:31.752 [main] DEBUG o.s.w.s.m.m.a.ResponseBodyAdviceChain - After ResponseBodyAdvice chain body=Curriculum [drivingLicense=true, smoker=false, maxNumberChildren=2, workExperienceInYears=11, dateOfBirth=1975-01-06 00:00:00.0, telephoneNumber=0142778899, firstName=Juliette, visible=true, validated=true]
16:54:31.767 [main] DEBUG o.s.w.s.m.m.a.ExceptionHandlerExceptionResolver - Resolving exception from handler [public com.bignibou.domain.Curriculum com.bignibou.controller.curriculum.CurriculumController.findCurriculumById(java.lang.Long)]: org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: failed to lazily initialize a collection of role: com.bignibou.domain.Curriculum.workExperiences, could not initialize proxy - no Session (through reference chain: com.bignibou.domain.Curriculum["workExperiences"]); nested exception is com.fasterxml.jackson.databind.JsonMappingException: failed to lazily initialize a collection of role: com.bignibou.domain.Curriculum.workExperiences, could not initialize proxy - no Session (through reference chain: com.bignibou.domain.Curriculum["workExperiences"])
16:54:31.768 [main] DEBUG o.s.w.s.m.a.ResponseStatusExceptionResolver - Resolving exception from handler [public com.bignibou.domain.Curriculum com.bignibou.controller.curriculum.CurriculumController.findCurriculumById(java.lang.Long)]: org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: failed to lazily initialize a collection of role: com.bignibou.domain.Curriculum.workExperiences, could not initialize proxy - no Session (through reference chain: com.bignibou.domain.Curriculum["workExperiences"]); nested exception is com.fasterxml.jackson.databind.JsonMappingException: failed to lazily initialize a collection of role: com.bignibou.domain.Curriculum.workExperiences, could not initialize proxy - no Session (through reference chain: com.bignibou.domain.Curriculum["workExperiences"])
16:54:31.768 [main] DEBUG o.s.w.s.m.s.DefaultHandlerExceptionResolver - Resolving exception from handler [public com.bignibou.domain.Curriculum com.bignibou.controller.curriculum.CurriculumController.findCurriculumById(java.lang.Long)]: org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: failed to lazily initialize a collection of role: com.bignibou.domain.Curriculum.workExperiences, could not initialize proxy - no Session (through reference chain: com.bignibou.domain.Curriculum["workExperiences"]); nested exception is com.fasterxml.jackson.databind.JsonMappingException: failed to lazily initialize a collection of role: com.bignibou.domain.Curriculum.workExperiences, could not initialize proxy - no Session (through reference chain: com.bignibou.domain.Curriculum["workExperiences"])
16:54:31.768 [main] DEBUG o.s.t.w.s.TestDispatcherServlet - Null ModelAndView returned to DispatcherServlet with name '': assuming HandlerAdapter completed request handling
16:54:31.768 [main] DEBUG o.s.t.w.s.TestDispatcherServlet - Successfully completed request
MockHttpServletRequest:
HTTP Method = GET
Request URI = /curriculum/findCurriculumById
Parameters = {id=[1]}
Headers = {Content-Type=[application/json], X-Ajax=[true]}
Handler:
Type = com.bignibou.controller.curriculum.CurriculumController
Method = public com.bignibou.domain.Curriculum com.bignibou.controller.curriculum.CurriculumController.findCurriculumById(java.lang.Long)
Async:
Was async started = false
Async result = null
Resolved Exception:
Type = org.springframework.http.converter.HttpMessageNotWritableException
ModelAndView:
View name = null
View = null
Model = null
FlashMap:
MockHttpServletResponse:
Status = 500
Error message = null
Headers = {Content-Type=[application/json]}
Content type = application/json
Body =
Forwarded URL = null
Redirected URL = null
Cookies = []
16:54:31.770 [main] DEBUG o.s.orm.jpa.JpaTransactionManager - Initiating transaction rollback
16:54:31.770 [main] DEBUG o.s.orm.jpa.JpaTransactionManager - Rolling back JPA transaction on EntityManager [[email protected]]
16:54:31.771 [main] DEBUG o.s.orm.jpa.JpaTransactionManager - Closing JPA EntityManager [[email protected]] after transaction
16:54:31.771 [main] DEBUG o.s.o.jpa.EntityManagerFactoryUtils - Closing JPA EntityManager
16:54:31.771 [main] DEBUG o.s.orm.jpa.JpaTransactionManager - Resuming suspended transaction after completion of inner transaction
16:54:31.771 [main] DEBUG o.s.orm.jpa.JpaTransactionManager - Creating new transaction with name [com.bignibouX.tests.security.curriculum.CurriculumPermissionEvaluatorAuthorizationTest.clean]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''
16:54:31.771 [main] DEBUG o.s.orm.jpa.JpaTransactionManager - Opened new EntityManager [[email protected]] for JPA transaction
16:54:31.771 [main] DEBUG o.s.orm.jpa.JpaTransactionManager - Exposing JPA transaction as JDBC transaction [org.springframewo[email protected]21bcecc5]
16:54:31.771 [main] DEBUG o.s.orm.jpa.JpaTransactionManager - Initiating transaction commit
16:54:31.772 [main] DEBUG o.s.orm.jpa.JpaTransactionManager - Committing JPA transaction on EntityManager [[email protected]]
16:54:31.772 [main] DEBUG o.s.orm.jpa.JpaTransactionManager - Closing JPA EntityManager [[email protected]] after transaction
編輯3:
這裏是課程的有關部分:
@Entity
public class Curriculum {
@OneToMany(cascade = CascadeType.ALL, mappedBy = "curriculum")
private Set<WorkExperience> workExperiences;
Sam:我很抱歉:我剛剛意識到用@Transactional註釋該方法實際上並沒有解決問題......我的錯誤是將答案標記爲首先被接受...... – balteo
我編輯過我的帖子有更多的信息。 – balteo
「curriculumService.findCurriculum(id)」的交易配置是什麼樣的?方法,類或接口是否用'@Transactional'註解,如果是的話,那麼'propagation'設置爲什麼? –