Problem with @OneToMany relations in a Generic CRUD

北战南征 提交于 2021-01-28 05:54:54

问题


I have this generic CRUD (Controller, Repository, Service, Specification) with multiple entities that use @OneToMany annotations. The project only starts when I comment on these annotations, otherwise I get an error that always indicates a different "DAO" file.

Struchture:

oga-servicio-principal
-src/main/java
--com.oga.springboot
---app.principal
----controllers
----crud (My Generic CRUD files)
-----controllers
-----models
------dao
------dto
------entity
------service
------specifications
----models
-----dao
-----dto
-----entity
-----service
---OgaServicioPrincipalApplication

The Console log

error log

Generic Controller:

//imports...

public class MyCrudController<T> {

    private IMyCrudService<T> service;

    @Setter
    protected T entity;

    public MyCrudController(IMyCrudService<T> service) {
        this.service = service;
    }

    @GetMapping
    public List<T> findAll(
            @RequestParam(value= "by", required = false) String prop,
            @RequestParam(value= "val", required = false) String value,
            @RequestParam(value= "sortby", required = false) String sort,
            @RequestParam(value= "sortdir", required = false) String dir
            ) {
        if(prop != null && value != null) {
            if(sort != null) {
                if(dir != null)
                    return service.findBySortDir(prop, ":", value, sort, dir);
                else
                    return service.findBySort(prop, ":", value, sort);
            }
            else
                return service.findBy(prop, ":", value);
                
        }
        else {
            if(sort != null) {
                if(dir != null)
                    return service.findAllSortDir(sort, dir);
                else
                    return service.findAllSort(sort);
            }
        } 
        return service.findAll();
    }

    @GetMapping("/{id}")
    public T findById(@PathVariable Integer id) {
        T entidadDb = service.findById(id);
        if (entidadDb == null)
            throw new ResponseStatusException(HttpStatus.NOT_FOUND, entity.getClass().getSimpleName() + " inexistente");
        else
            return entidadDb;
    }

    @PostMapping
    @ResponseStatus(HttpStatus.CREATED)
    public T create(@RequestBody T ent) {
        return service.save(ent);
    }

    @DeleteMapping("/{id}")
    @ResponseStatus(HttpStatus.OK)
    public void deleteById(@PathVariable Integer id) {
        Boolean existe = service.existsById(id);
        if (existe == true)
            service.deleteById(id);
        else
            throw new ResponseStatusException(HttpStatus.NOT_FOUND, entity.getClass().getSimpleName() + " inexistente");
    }

    @PutMapping("/{id}")
    @ResponseStatus(HttpStatus.CREATED)
    public T update(@RequestBody T entidad, @PathVariable Integer id) {
        T entidadDb = service.findById(id);
        if (entidadDb == null)
            throw new ResponseStatusException(HttpStatus.NOT_FOUND, entity.getClass().getSimpleName() + " inexistente");
        else {
            BeanUtils.copyProperties(entidad, entidadDb, "id");
            return service.save(entidadDb);
        }
    }
    
}

Generic DAO

package com.oga.springboot.app.principal.crud.models.dao;

//import 

@NoRepositoryBean
public interface IMyCrudDao<T> extends PagingAndSortingRepository<T, Integer>, JpaSpecificationExecutor<T>{}

Generic Service Interface

package com.oga.springboot.app.principal.crud.models.service;

import java.util.List;

public interface IMyCrudService<T> {
    public List<T> findAll();
    public List<T> findAllSort(String sortField);
    public List<T> findAllSortDir(String sortField, String direction);
    public List<T> findBySort(String prop, String op, String value, String sortField);
    public List<T> findBySortDir(String prop, String op, String value, String sortField, String direction);
    public T findById(Integer id);
    public List<T> findBy(String prop, String op, String value);
    public T save(T entity);
    public void deleteById(Integer id);
    public boolean existsById(Integer id);
}

Generic Service Implementation

package com.oga.springboot.app.principal.crud.models.service;

// imports...

@Service
public class MyCrudServiceImpl<T> implements IMyCrudService<T> {

    @Setter
    protected IMyCrudDao<T> dao;

    @Override
    @Transactional(readOnly = true)
    public List<T> findAll() {
        return (List<T>) dao.findAll();
    }

    @Override
    public List<T> findAllSort(String sortField) {
        return (List<T>) dao.findAll(Sort.by(sortField));
    }

    @Override
    public List<T> findAllSortDir(String sortField, String direction) {
        return (List<T>) dao.findAll(Sort.by(Sort.Direction.fromString(direction), sortField));
    }
    
    @Override
    public List<T> findBy(String prop, String op, String value) {
        MyCrudSpecification<T> spec = new MyCrudSpecification<T>(new SearchCriteria(prop, op, value));
        return dao.findAll(spec);
    }
    
    @Override
    public List<T> findBySort(String prop, String op, String value, String sortField) {
        MyCrudSpecification<T> spec = new MyCrudSpecification<T>(new SearchCriteria(prop, op, value));
        return dao.findAll(spec, Sort.by(sortField));
    }
    
    @Override
    public List<T> findBySortDir(String prop, String op, String value, String sortField, String direction) {
        MyCrudSpecification<T> spec = new MyCrudSpecification<T>(new SearchCriteria(prop, op, value));
        return (List<T>) dao.findAll(spec, Sort.by(Sort.Direction.fromString(direction), sortField));
    }

    @Override
    public T findById(Integer id) {
        return dao.findById(id).orElse(null);
    }

    @Override
    @Transactional
    public T save(T entity) {
        return dao.save(entity);
    }

    @Override
    @Transactional
    public void deleteById(Integer id) {
        dao.deleteById(id);
    }

    @Override
    @Transactional(readOnly = true)
    public boolean existsById(Integer id) {
        return dao.existsById(id);
    }

}

Generic Specification

package com.oga.springboot.app.principal.crud.models.specifications;

//imports

@SuppressWarnings("serial")
public class MyCrudSpecification<T> implements Specification<T> {

    private SearchCriteria criteria;

    public MyCrudSpecification(SearchCriteria searchCriteria) {
        this.criteria = searchCriteria;
    }

    @Override
    public Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
        if (criteria.getOperation().equalsIgnoreCase(">")) {
            return criteriaBuilder.greaterThanOrEqualTo(root.<String>get(criteria.getKey()),
                    criteria.getValue().toString());
        } else if (criteria.getOperation().equalsIgnoreCase("<")) {
            return criteriaBuilder.lessThanOrEqualTo(root.<String>get(criteria.getKey()),
                    criteria.getValue().toString());
        } else if (criteria.getOperation().equalsIgnoreCase(":")) {
            if (root.get(criteria.getKey()).getJavaType() == String.class)
                return criteriaBuilder.like(root.<String>get(criteria.getKey()), "%" + criteria.getValue() + "%");
            else if (root.get(criteria.getKey()).getJavaType().isAnnotationPresent(Entity.class))
                return criteriaBuilder.equal(root.get(criteria.getKey()).get("id"), criteria.getValue());
            else
                return criteriaBuilder.equal(root.get(criteria.getKey()), criteria.getValue());
        }
        return null;
    }

}

Particular extends for Controller, Service, Dao

//AudienciaTipoController.java

package com.oga.springboot.app.principal.controllers;

//imports
@RestController
@RequestMapping("audiencia-tipo")
public class AudienciaTipoController extends MyCrudController<AudienciaTipo> {

    @Autowired
    public AudienciaTipoController(@Qualifier("audienciaTipoServiceImpl") IMyCrudService<AudienciaTipo> myService) {
        super(myService);
        AudienciaTipo entity = new AudienciaTipo();
        this.setEntity(entity);
    }
}

------------------

//IAudienciaTipoDao.java

package com.oga.springboot.app.principal.models.dao;

///imports

@Repository
public interface IAudienciaTipoDao extends IMyCrudDao<AudienciaTipo>{}

-------------------------

// IAudienciaTipoService.java

package com.oga.springboot.app.principal.models.service;

//imports

public interface IAudienciaTipoService extends IMyCrudService<AudienciaTipo>{}

--------------------------

// AudienciaTipoServiceImpl.java

package com.oga.springboot.app.principal.models.service;

//imports

@Service
public class AudienciaTipoServiceImpl extends MyCrudServiceImpl<AudienciaTipo> implements IAudienciaTipoService{
    
    @Autowired
    public AudienciaTipoServiceImpl(IAudienciaTipoDao dao) {
        super();
        this.setDao(dao);
    }
}

Some Entities

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package com.oga.springboot.app.principal.models.entity;

//imports

@Entity
@Table(name = "audiencia_tipos", uniqueConstraints = {
    @UniqueConstraint(columnNames = {"descripcion"}),
    @UniqueConstraint(columnNames = {"invenietid"})})
@NamedQueries({
    @NamedQuery(name = "AudienciaTipo.findAll", query = "SELECT a FROM AudienciaTipo a")})
public class AudienciaTipo implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Basic(optional = false)
    @Column(nullable = false)
    private Integer id;
    
    @Basic(optional = false)
    @NotNull
    @Size(min = 1, max = 250)
    @Column(nullable = false, length = 250)
    private String descripcion;
    
    @Basic(optional = false)
    @NotNull
    @Column(nullable = false)
    private short tiempo;
    
    @Basic(optional = false)
    @NotNull
    @Column(nullable = false)
    private short activo;
    
    private Integer invenietid;
    
    @OneToMany(cascade = CascadeType.ALL, mappedBy = "tipoid")
    private List<JuezTipoAudiencia> juezTipoAudienciasList;
    
    @OneToMany(cascade = CascadeType.ALL, mappedBy = "audienciaTipoid")
    private List<AudienciaTipoAudiencia> audienciaTipoAudienciasList;
    
    @JoinColumn(name = "categoriaid", referencedColumnName = "id")
    @ManyToOne
    private Categoria categoriaid;
    
    @JoinColumn(name = "prioridadid", referencedColumnName = "id", nullable = false)
    @ManyToOne(optional = false)
    private Prioridad prioridadid;
    
    @JoinColumn(name = "usuarioid", referencedColumnName = "id", nullable = false)
    @ManyToOne(optional = false)
    private Usuario usuarioid;

    public AudienciaTipo() {
    }

    public AudienciaTipo(Integer id) {
        this.id = id;
    }

    public AudienciaTipo(Integer id, String descripcion, short tiempo, short activo) {
        this.id = id;
        this.descripcion = descripcion;
        this.tiempo = tiempo;
        this.activo = activo;
    }

   //Getter and Setters

    @Override
    public int hashCode() {
        int hash = 0;
        hash += (id != null ? id.hashCode() : 0);
        return hash;
    }

    @Override
    public boolean equals(Object object) {
        // TODO: Warning - this method won't work in the case the id fields are not set
        System.out.println("<--- EQUALS ---->");
        System.out.println(this.toString());
        if (!(object instanceof AudienciaTipo)) {
            return false;
        }
        AudienciaTipo other = (AudienciaTipo) object;
        if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id))) {
            return false;
        }
        return true;
    }

    @Override
    public String toString() {
        return "com.mycompany.inversaoga.AudienciaTipos[ id=" + id + " ]";
    }
    
}

package com.oga.springboot.app.principal.models.entity;

//imports...

@Entity
@Table(name = "juez_tipo_audiencias")
@NamedQueries({
    @NamedQuery(name = "JuezTipoAudiencia.findAll", query = "SELECT j FROM JuezTipoAudiencia j")})
public class JuezTipoAudiencia implements Serializable {

    private static final long serialVersionUID = 1L;
    
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Basic(optional = false)
    @Column(nullable = false)
    private Integer id;
    
    @JoinColumn(name = "tipoid", referencedColumnName = "id", nullable = false)
    @ManyToOne(optional = false)
    private AudienciaTipo tipoid;
    
    @JoinColumn(name = "juezid", referencedColumnName = "id", nullable = false)
    @ManyToOne(optional = false)
    private Juez juezid;

    public JuezTipoAudiencia() {
    }

    public JuezTipoAudiencia(Integer id) {
        this.id = id;
    }


    @Override
    public int hashCode() {
        int hash = 0;
        hash += (id != null ? id.hashCode() : 0);
        return hash;
    }

    @Override
    public boolean equals(Object object) {
        // TODO: Warning - this method won't work in the case the id fields are not set
        if (!(object instanceof JuezTipoAudiencia)) {
            return false;
        }
        JuezTipoAudiencia other = (JuezTipoAudiencia) object;
        if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id))) {
            return false;
        }
        return true;
    }

    @Override
    public String toString() {
        return "com.mycompany.inversaoga.JuezTipoAudiencias[ id=" + id + " ]";
    }
    
}

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.1.RELEASE</version>
        <relativePath /> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.oga.springboot.app.principal</groupId>
    <artifactId>oga-servicio-principal</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>oga-servicio-principal</name>
    <description>principal</description>

    <properties>
        <java.version>1.8</java.version>
        <spring-cloud.version>Hoxton.SR5</spring-cloud.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.postgresql</groupId>
            <artifactId>postgresql</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
        </dependency>
        <dependency>
            <groupId>org.modelmapper</groupId>
            <artifactId>modelmapper</artifactId>
            <version>2.3.8</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-mail</artifactId>
        </dependency>
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

OgaServicioPrincipalApplication.java

package com.oga.springboot;

//imports...

@SpringBootApplication
@EnableEurekaClient
public class OgaServicioPrincipalApplication {

    public static void main(String[] args) {
        SpringApplication.run(OgaServicioPrincipalApplication.class, args);
    }
    
    @Bean
    public ModelMapper modelMapper() {
        return new ModelMapper();
    }

}

application.properties

spring.application.name=oga-servicio-principal
server.port=8091
eureka.instance.instance-id=${spring.application.name}:${spring.application.instance_id:${random.value}}
eureka.client.service-url.defaultZone=http://localhost:8761/eureka

spring.datasource.url=jdbc:postgresql://localhost:5432/database_name
spring.datasource.username=user
spring.datasource.password=password
spring.datasource.driver-class-name=org.postgresql.Driver
spring.jpa.database-platform=org.hibernate.dialect.PostgreSQL95Dialect
spring.jpa.hibernate.ddl-auto=none
spring.jpa.show-sql=true
logging.level.org.hibernate.SQL=debug

spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true

hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds: 20000
ribbon.ConnectTimeout: 3000
ribbon.ReadTimeout: 10000

来源:https://stackoverflow.com/questions/63166540/problem-with-onetomany-relations-in-a-generic-crud

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!