5

Backend Spring MVC e Spring-data, spring-security. Front-end Angularj. Sto usando spring 3.1; Jackson 1.8; JPa 2.1 ands mysql.Il problema di base è lo stesso di quello richiesto più volte. Ho un programma semplice con due siti POJOs e typeSite- dove un tipoSite può avere più siti. Ma sto ottenendo il seguente errore:Jackson ha confuso con la relazione bidirezionale uno-a-molti: non è riuscito a inizializzare la raccolta

org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: failed to lazily initialize a collection of role: TypeSites.sitees, could not initialize proxy - no Session (through reference chain: vo.TypeSitesListVO["typesites"]->java.util.UnmodifiableRandomAccessList[0]-model.TypeSites["sitees"]); nested exception is com.fasterxml.jackson.databind.JsonMappingException: failed to lazily initialize a collection of role: model.TypeSites.sitees, could not initialize proxy - no Session (through reference chain:vo.TypeSitesListVO["typesites"]->java.util.UnmodifiableRandomAccessList[0]->model.TypeSites["sitees"]) 
Caused by: com.fasterxml.jackson.databind.JsonMappingException: failed to lazily initialize a collection of role: model.TypeSites.sitees, could not initialize proxy - no Session (through reference chain: vo.TypeSitesListVO["typesites"]->java.util.UnmodifiableRandomAccessList[0]->model.TypeSites["sitees"]) 

E questa seguente errore in del browser:

Failed to load resource: the server responded with a status of 500 (Internal Server Error) 

Quindi, per comprendere meglio questo errore vediamo come l'APP/Hibernate gestisce il rapporto. Ogni volta che eseguiamo una query nel database, il JPA porterà a tutte le informazioni di quella classe. L'eccezione a questa regola è quando parliamo di lista (raccolta). Nota nel codice precedente, che la query del database restituirà un oggetto Sites. Quando accedo alla raccolta siti, il contenitore noterà che la raccolta siti è un attributo lazy e chiederà al JPA di caricare questa raccolta dal database.

Al momento dell'esecuzione della query (che porterà la raccolta del sito), si verificherà un'eccezione. Quando JPA/Hibernate tenta di accedere al database per ottenere queste informazioni pigre, il JPA noterà che non esiste una raccolta aperta. Ecco perché accade l'eccezione, la mancanza di una connessione di database aperta.

classe del modello:

@JsonIgnoreProperties({ "hibernateLazyInitializer", "handler" }) 
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property="id") 
public class Sites implements java.io.Serializable { 

    private static final long serialVersionUID = 1L; 
    private int     id; 
    private TypeSites   siteesTypeSite; 
    @Id 
    @GeneratedValue(strategy = GenerationType.AUTO) 
    public int getId() { 
     return id; 
    } 
    //@ManyToOne(fetch = FetchType.LAZY) 
    //@JoinColumn(name ="idTypeSite") 
    //@JsonIgnore 
    @JsonBackReference("site-typeSite") 
    @ManyToOne 
    @JoinColumn(name = "idTypeSite", foreignKey = @ForeignKey(name = "fk_site_typeSite")) 
    public TypeSites getSiteesTypeSite() { 
     return siteesTypeSite; 
    } 
@JsonIgnoreProperties({ "hibernateLazyInitializer", "handler" }) 
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property="idTypeSite") 
public class TypeSites implements java.io.Serializable { 
    private int      idTypeSite; 
    private Set<Sites>    sitees= new HashSet<Sites>(0); 

    @Id 
    @GeneratedValue(strategy = GenerationType.AUTO) 
    public int getIdTypeSite() { 
     return idTypeSite; 
    } 
    //@JsonSerialize(using = CustomListSerializer.class) 
    //@JsonView(Views.Internal.class) 
    //@JsonIgnore 
    @JsonManagedReference("site-typeSite") 
    @OneToMany(mappedBy = "siteesTypeSite", cascade = CascadeType.ALL,fetch = FetchType.LAZY) 
    public Set<Sites> getSitees() { 
     return sitees; 
    } 

codice di modello di progettazione oggetto valore

public class TypeSitesListVO { 
    private int   pagesCount; 
    private long  totalTypeSite; 
    private String  actionMessage; 
    private String  searchMessage; 
    private List<TypeSites> typesites; 
    //setters/gtters} 
public class SitesListVO { 
    private int pagesCount; 
    private long totalSites; 
    private String actionMessage; 
    private String searchMessage; 
    private List<Sites> sites = new ArrayList<Sites>(); 
    //setters/gtters} 

Repository:

public interface SitesRepository extends PagingAndSortingRepository<Sites, Integer> { 
    //@Query("SELECT s FROM Sites s TypeSites ts JOIN FETCH s.siteesTypeSite WHERE s.id =ts.idTypeSite ") 
    //@EntityGraph(value = "sites.type", type = EntityGraphType.LOAD) 
    Page<Sites> findBycodeGSMLike(Pageable pageable, String codeGSM); 
    //Page<Sites> findBycodeGSMLike(Pageable pageable, List<String> codeGSM); 
} 

Servizi classe:

@Service 
@Transactional 
public class SitesService { 
    @Autowired 
    private SitesRepository siteRepository; 
    @Transactional(readOnly = true) 
    public SitesListVO findAll(int page, int maxResults) { 
     Page<Sites> result = executeQueryFindAll(page, maxResults); 
       if(shouldExecuteSameQueryInLastPage(page, result)){ 
       int lastPage = result.getTotalPages() - 1; 
    //   for (Sites e: result){ 
    //    Hibernate.initialize(e.getSiteesTypeSite()); 
    //   } 
       result = executeQueryFindAll(lastPage, maxResults); 
      } 
      return buildResult(result); 
     } 
     public void save(Sites site) { 
      siteRepository.save(site); 
     } 
     @Transactional(readOnly = true) 
     public SitesListVO findBycodeGSMLike(int page, int maxResults, String codeGSM) { 
      Page<Sites> result = executeQueryFindByName(page, maxResults, codeGSM); 

      if(shouldExecuteSameQueryInLastPage(page, result)){ 
       int lastPage = result.getTotalPages() - 1; 
    //   for (Sites e: result){ 
    //    Hibernate.initialize(e.getSiteesTypeSite()); 
    //   } 
       result = executeQueryFindByName(lastPage, maxResults, codeGSM); 
      } 
      return buildResult(result); 
     } 
     private boolean shouldExecuteSameQueryInLastPage(int page, Page<Sites> result) { 
      return isUserAfterOrOnLastPage(page, result) && hasDataInDataBase(result); 
     } 
     private Page<Sites> executeQueryFindAll(int page, int maxResults) { 
      final PageRequest pageRequest = new PageRequest(page, maxResults, sortBycodeGSMASC()); 
    //  Page<Sites> SitesList = siteRepository.findAll(pageRequest); 
    //  for (Sites e: SitesList){ 
    //   Hibernate.initialize(e.getSiteesTypeSite()); 
    //  } 
    //  return SitesList; 
      return siteRepository.findAll(pageRequest); 
     } 

     private Sort sortBycodeGSMASC() { 
      return new Sort(Sort.Direction.ASC, "codeGSM"); 
     } 

     private SitesListVO buildResult(Page<Sites> result) { 

      return new SitesListVO(result.getTotalPages(), result.getTotalElements(), result.getContent()); 
     } 

     private Page<Sites> executeQueryFindByName(int page, int maxResults, String codeGSM) { 
      final PageRequest pageRequest = new PageRequest(page, maxResults, sortBycodeGSMASC()); 

    //  Page<Sites> SitesList = siteRepository.findBycodeGSMLike(pageRequest, codeGSM); 
    //  for (Sites e: SitesList){ 
    //   Hibernate.initialize(e.getSiteesTypeSite()); 
    //  } 
    //  return SitesList; 
      return siteRepository.findBycodeGSMLike(pageRequest, codeGSM); 
     } 
     private boolean isUserAfterOrOnLastPage(int page, Page<Sites> result) { 
      return page >= result.getTotalPages() - 1; 
     } 

     private boolean hasDataInDataBase(Page<Sites> result) { 
      return result.getTotalElements() > 0; 
     } 
    } 
Classe

regolatore: codice

@Controller 
@RequestMapping(value = "/protected/sites") 
public class SitesController { 
    private static final String DEFAULT_PAGE_DISPLAYED_TO_USER = "0"; 
    @Autowired 
    private SitesService siteService; 
    @Autowired 
    private MessageSource messageSource; 

    @Value("5") 
    private int maxResults; 

    @RequestMapping(method = RequestMethod.GET) 
    public ModelAndView welcome() { 
     return new ModelAndView("sitesList"); 
    } 
    @RequestMapping(method = RequestMethod.GET, produces = "application/json") 
    public ResponseEntity<?> listAll(@RequestParam int page, Locale locale) { 

     return createListAllResponse(page, locale); 
    } 

    @RequestMapping(method = RequestMethod.POST, produces = "application/json") 
    public ResponseEntity<?> create(@ModelAttribute("site") Sites site, 
            @RequestParam(required = false) String searchFor, 
            @RequestParam(required = false, 
            defaultValue = DEFAULT_PAGE_DISPLAYED_TO_USER) int page, 
            Locale locale) { 
     siteService.save(site); 

     if (isSearchActivated(searchFor)) { 
      return search(searchFor, page, locale, "message.create.success"); 
     } 

     return createListAllResponse(page, locale, "message.create.success"); 
    } 


    private SitesListVO listAll(int page) { 
     return siteService.findAll(page, maxResults); 
    } 
    private ResponseEntity<SitesListVO> returnListToUser(SitesListVO siteList) { 
     return new ResponseEntity<SitesListVO>(siteList, HttpStatus.OK); 
    } 
    private ResponseEntity<?> createListAllResponse(int page, Locale locale) { 
     SitesListVO siteListVO = listAll(page); 
     return createListAllResponse(page, locale, null); 
    } 

    private ResponseEntity<?> createListAllResponse(int page, Locale locale, String messageKey) { 
     SitesListVO siteListVO = listAll(page); 
     addActionMessageToVO(siteListVO, locale, messageKey, null); 
     return returnListToUser(siteListVO); 
    } 
    private SitesListVO addActionMessageToVO(SitesListVO siteListVO, Locale locale, String actionMessageKey, Object[] args) { 
     if (StringUtils.isEmpty(actionMessageKey)) { 
      return siteListVO; 
     } 
     siteListVO.setActionMessage(messageSource.getMessage(actionMessageKey, args, null, locale)); 
     return siteListVO; 
    } 
    private SitesListVO addSearchMessageToVO(SitesListVO siteListVO, Locale locale, String actionMessageKey, Object[] args) { 
     if (StringUtils.isEmpty(actionMessageKey)) { 
      return siteListVO; 
     } 
     siteListVO.setSearchMessage(messageSource.getMessage(actionMessageKey, args, null, locale)); 
     return siteListVO; 
    } 
    private boolean isSearchActivated(String searchFor) { 
     //return !CollectionUtils.isEmpty(searchFor); 
     return !StringUtils.isEmpty(searchFor); 
    } 
} 

AngularJs:

$scope.getContactList = function() { 
     var url = $scope.url; 
     $scope.lastAction = 'list'; 

     $scope.startDialogAjaxRequest(); 

     var config = {params: {page: $scope.pageToGet}}; 

     $http.get(url, config) 

      .success(function (data) { 
//    console.log(data); 
       console.debug(data); 
       $scope.finishAjaxCallOnSuccess(data, null, false); 
      }) 
      .error(function() { 
       $scope.state = 'error'; 
       $scope.displayCreateContactButton = false; 
      }); 
    } 
$scope.populateTable = function (data) { 
      if (data.pagesCount > 0) { 
       $scope.state = 'list'; 

       $scope.page = {source: data.sites, currentPage: $scope.pageToGet, pagesCount: data.pagesCount, totalContacts : data.totalContacts}; 

       if($scope.page.pagesCount <= $scope.page.currentPage){ 
        $scope.pageToGet = $scope.page.pagesCount - 1; 
        $scope.page.currentPage = $scope.page.pagesCount - 1; 
       } 

       $scope.displayCreateContactButton = true; 
       $scope.displaySearchButton = true; 
      } else { 
       $scope.state = 'noresult'; 
       $scope.displayCreateContactButton = true; 

       if(!$scope.searchFor){ 
        $scope.displaySearchButton = false; 
       } 
      } 
      if (data.actionMessage || data.searchMessage) { 
       $scope.displayMessageToUser = $scope.lastAction != 'search'; 

       $scope.page.actionMessage = data.actionMessage; 
       $scope.page.searchMessage = data.searchMessage; 
      } else { 
       $scope.displayMessageToUser = false; 
      } 
    } 

In XML MVC primavera ho:

<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"> 
    <property name="messageConverters"> 
     <list> 

      <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"> 
       <property name="objectMapper"> 
        <bean class="filter.HibernateAwareObjectMapper" /> 
       </property> 
      </bean> 
      <bean class="org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter"/> 
     </list> 
    </property> 
</bean> 

Codice di Classe HibernateAwareObjectMapper: public class HibernateAwareObjectMapper estende ObjectMapper {

private static final long serialVersionUID = 1L; 

    public HibernateAwareObjectMapper() { 
     registerModule(new Hibernate4Module()); 
    } 

} 

Web XML ho questo filtro:

<filter> 
     <filter-name>springSecurityFilterChain</filter-name> 
     <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> 
    </filter> 
    <filter-mapping> 
     <filter-name>springSecurityFilterChain</filter-name> 
     <url-pattern>/*</url-pattern> 
    </filter-mapping> 

; sto usando la seguente dipendenza:

<dependency> 
    <groupId>org.codehaus.jackson</groupId> 
    <artifactId>jackson-mapper-asl</artifactId> 
    <version>1.9.13</version> 
</dependency> 
<dependency> 
    <groupId>com.fasterxml.jackson.core</groupId> 
    <artifactId>jackson-databind</artifactId> 
    <version>2.3.3</version> 
</dependency> 
<dependency> 
    <groupId>com.fasterxml.jackson.core</groupId> 
    <artifactId>jackson-annotations</artifactId> 
    <version>2.3.0</version> 
</dependency> 
<dependency> 
     <groupId>com.fasterxml.jackson.datatype</groupId> 
     <artifactId>jackson-datatype-hibernate4</artifactId> 
     <version>2.4.0</version> 
</dependency> 

c'è un modo per caricare la raccolta da Open Session? grazie in anticipo per il replay

risposta

0

Una possibilità è aggiungere OpenEntityManagerInViewFilter che mantiene aperta la sessione nella vista.Esempio:

<filter> 
    <filter-name>Spring OpenEntityManagerInViewFilter</filter-name> 
    <filter-class>org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter</filter-class> 
</filter> 

<filter-mapping> 
    <filter-name>Spring OpenEntityManagerInViewFilter</filter-name> 
    <url-pattern>/*</url-pattern> 
</filter-mapping> 
+1

Thank u per il replay, ho già provare questo mantenendo entrambi filtro, ma ho ottenuto lo stesso errore, ma quando rimuovo il mio filtro non riesco ad accedere alla mia pagina di accesso perché uso la sicurezza di primavera ho un altro errore; è il seguente: java.lang.NullPointerException \t a interceptor.LoginInterceptor.preHandle (LoginInterceptor.java:27) \t a org.springframework. web.servlet.HandlerExecutionChain.applyPreHandle ( – Ahmed

10

risolvo che con l'aggiunta di questa annotazione @LazyCollection(LazyCollectionOption.FALSE)

//@JsonSerialize(using = CustomListSerializer.class) 
    //@JsonView(Views.Internal.class) 
    //@JsonIgnore 
    @LazyCollection(LazyCollectionOption.FALSE) 
    @OneToMany(mappedBy = "siteesTypeSite", cascade = CascadeType.ALL,fetch = FetchType.LAZY) 
    public Set<Sites> getSitees() { 
     return sitees; 
    } 
Problemi correlati