java.lang.IllegalArgumentException: The given domain class does not contain an id attribute!

O erro que está sendo reportado é devido a falta de Id? Ou esse select que fiz está errado?

@Entity
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class FechamentoCaixa implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @CreationTimestamp
    private LocalDateTime dateFechamentoCaixa;

    @UpdateTimestamp
    private LocalDateTime dateAtualizacaoFechamentoCaixa;

    @Column(name = "filial_id")
    private Long idFilial;

    @Column(name = "user_id")
    private Long idUser;

    @Column(name = "observacao")
    private String observacao;

    @ElementCollection(fetch = FetchType.LAZY)
    @CollectionTable(name = "fechamentoCaixaItens", joinColumns = @JoinColumn(name = "fechamento_caixa_id"))
    private Set<FechamentoCaixaItem> produtos = new HashSet<>();
    public FechamentoCaixa(long idFilial, long idUser, Set<FechamentoCaixaItem> produtos) {
        this.idFilial = idFilial;
        this.idUser = idUser;
        this.produtos = produtos;
    }
}
@Embeddable
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class FechamentoCaixaItem {
    private Long id;
    private int inicio;
    private int entrada;
    private int perda;
    private int quantidadeFinal;

    public FechamentoCaixaItem(FechamentoCaixaItemDto fechamentoCaixa) {
        this.id = fechamentoCaixa.getId();
        this.inicio = fechamentoCaixa.getInicio();
        this.entrada = fechamentoCaixa.getEntrada();
        this.perda = fechamentoCaixa.getPerda();
        this.quantidadeFinal = fechamentoCaixa.getQuantidadeFinal();
    }
}
@RestController
public class FechamentoCaixaController {
//codigo ignorado

    @GetMapping("/buscaFechamentoCaixaProduto/{idFilial}/{idProduto}/{dataInicial}/{dataFinal}")
    public ResponseEntity<Object> buscaFechamentoCaixaProduto(@PathVariable(value = "idFilial") Long idFilial,
                                                              @PathVariable(value = "idProduto") Long idProduto,
                                                              @PathVariable(value = "dataInicial") @DateTimeFormat(pattern = "yyyy-MM-dd")  String dataInicial,
                                                              @PathVariable(value = "dataFinal") @DateTimeFormat(pattern = "yyyy-MM-dd") String dataFinal) throws ParseException {
        FechamentoCaixaItem optionalFechamentoCaixaItem = fechamentoCaixaItemService.selectFechamentoCaixaProduto(idFilial, idProduto, Util.dateToTimestamp(dataInicial), Util.dateToTimestamp(dataFinal));
        if (optionalFechamentoCaixaItem != null) {
            return ResponseEntity.status(HttpStatus.OK).body(optionalFechamentoCaixaItem);
        }
        return ResponseEntity.status(HttpStatus.NOT_FOUND).body("FECHAMENTO_CAIXA_NAO_ENCONTRADO");
    }   
}
@Service
public class FechamentoCaixaItemServiceImpl implements FechamentoCaixaItemService{
    final FechamentoCaixaItemRepository fechamentoCaixaItemRepository;    

    @Override
    public FechamentoCaixaItem selectFechamentoCaixaProduto(Long filialId, Long produtoId, Timestamp dataInicial, Timestamp dataFinal) {
        return fechamentoCaixaItemRepository.selectFechamentoCaixaProduto(filialId, produtoId, dataInicial, dataFinal);
    }
}
@Repository
public interface FechamentoCaixaItemRepository extends JpaRepository<FechamentoCaixaItem, Long> {

        @Transactional
        @Modifying
        @Query(value = "select fechamento_caixa_itens.* " +
                "from fechamento_caixa , fechamento_caixa_itens " +
                "where fechamento_caixa.id = fechamento_caixa_itens.fechamento_caixa_id " +
                "and fechamento_caixa.filial_id = :filialId " +
                "and fechamento_caixa_itens.id = :produtoId " +
                "and fechamento_caixa.date_fechamento_caixa between :dataInicial and :dataFinal", nativeQuery = true)
        FechamentoCaixaItem selectFechamentoCaixaProduto(Long filialId, Long produtoId, Timestamp dataInicial, Timestamp dataFinal);
}

e estou obtendo isso no run do projeto:

Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled. 2023-01-09 00:37:31.697 ERROR 11632 --- [ restartedMain] o.s.boot.SpringApplication : Application run failed

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'fechamentoCaixaController' defined in file [E:\projetos\parcao-back\target\classes\com\parcao\controllers\FechamentoCaixaController.class]: Unsatisfied dependency expressed through constructor parameter 1; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'fechamentoCaixaItemServiceImpl' defined in file [E:\projetos\parcao-back\target\classes\com\parcao\security\services\FechamentoCaixaItemServiceImpl.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'fechamentoCaixaItemRepository' defined in com.parcao.repository.FechamentoCaixaItemRepository defined in @EnableJpaRepositories declared on JpaRepositoriesRegistrar.EnableJpaRepositoriesConfiguration: Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: The given domain class does not contain an id attribute!

Poderiam me ajudar a apontar onde estou errando?

Parece que vc está tentando retornar uma classe que não é uma entidade JPA válida: FechamentoCaixaItem.

Repositório serve para trabalhar com entidades do banco. Caso vc precise fazer algo com alguma classe que não seja uma entidade, vc deve fazer de forma explicita. No seu caso, vc não conseguirá isso com o spring-data diretamente.

Obrigado pelo retorno. E como seria de forma explícita @Lucas_Camara ?

Com spring-data, vc conseguiria instanciar uma classe que não é entidade para ser o retorno da consulta:

SELECT new pacote.da.classe.SuaClasse(t.a, t.b)
FROM SuaEntidade t

Para isso, seria necessário ter um construtor para receber os devidos valores.


Porém, no seu caso, acredito que essa classe FechamentoCaixaItem seria uma entidade referente à tabela fechamento_caixa_itens, certo? Se for, basta vc mapear ela que vc irá conseguir fazer a consulta de boas.

Como seria esse mapeamento?

Uma classe para ser uma entidade JPA, deve ser mapeada com o @Entity e @Id.

Deu certo deixando assim:

@Entity
@Embeddable
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class FechamentoCaixaItem {
    @Id
    private Long id;
    private int inicio;
    private int entrada;
    private int perda;
    private int quantidadeFinal;

    public FechamentoCaixaItem(FechamentoCaixaItemDto fechamentoCaixa) {
        this.id = fechamentoCaixa.getId();
        this.inicio = fechamentoCaixa.getInicio();
        this.entrada = fechamentoCaixa.getEntrada();
        this.perda = fechamentoCaixa.getPerda();
        this.quantidadeFinal = fechamentoCaixa.getQuantidadeFinal();
    }
}

mas quebrou meu POST:

@PostMapping("/create")
    public ResponseEntity<?> createFechamentoCaixa(@Valid @RequestBody FechamentoCaixaDto fechamentoCaixaDto) {
        Set<FechamentoCaixaItemDto> produtoItemFechamentoCaixaDto = fechamentoCaixaDto.getProdutos();
        Set<FechamentoCaixaItem> produtos = new HashSet<>();

        produtoItemFechamentoCaixaDto.forEach(produto -> produtos.add(produtoService.existsById(produto.getId()) ? new FechamentoCaixaItem(produto) : null));

        FechamentoCaixa fechamentoCaixa = new FechamentoCaixa();
        BeanUtils.copyProperties(fechamentoCaixaDto, fechamentoCaixa);
        fechamentoCaixa.setProdutos(produtos);
        return ResponseEntity.status(HttpStatus.CREATED).body(fechamentoCaixaService.save(fechamentoCaixa));
    }

e recebo isso de erro
org.hibernate.tool.schema.spi.CommandAcceptanceException: Error executing DDL "
alter table fechamento_caixa_itens
add constraint FKqnskj7tx5vpilw3iymft473ti
foreign key (produtos_id)
references fechamento_caixa_item" via JDBC Statement
at org.hibernate.tool.schema.internal.exec.GenerationTargetToDatabase.accept(GenerationTargetToDatabase.java:67) ~[hibernate-core-5.6.4.Final.jar:5.6.4.Final]
at org.hibernate.tool.schema.internal.AbstractSchemaMigrator.applySqlString(AbstractSchemaMigrator.java:581) ~[hibernate-core-5.6.4.Final.jar:5.6.4.Final]
at org.hibernate.tool.schema.internal.AbstractSchemaMigrator.applySqlStrings(AbstractSchemaMigrator.java:526) ~[hibernate-core-5.6.4.Final.jar:5.6.4.Final]
at org.hibernate.tool.schema.internal.AbstractSchemaMigrator.applyForeignKeys(AbstractSchemaMigrator.java:452) ~[hibernate-core-5.6.4.Final.jar:5.6.4.Final]
at org.hibernate.tool.schema.internal.AbstractSchemaMigrator.performMigration(AbstractSchemaMigrator.java:263) ~[hibernate-core-5.6.4.Final.jar:5.6.4.Final]
at org.hibernate.tool.schema.internal.AbstractSchemaMigrator.doMigration(AbstractSchemaMigrator.java:123) ~[hibernate-core-5.6.4.Final.jar:5.6.4.Final]
at org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator.performDatabaseAction(SchemaManagementToolCoordinator.java:192) ~[hibernate-core-5.6.4.Final.jar:5.6.4.Final]
at org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator.process(SchemaManagementToolCoordinator.java:81) ~[hibernate-core-5.6.4.Final.jar:5.6.4.Final]
at org.hibernate.internal.SessionFactoryImpl.(SessionFactoryImpl.java:335) ~[hibernate-core-5.6.4.Final.jar:5.6.4.Final]
at org.hibernate.boot.internal.SessionFactoryBuilderImpl.build(SessionFactoryBuilderImpl.java:471) ~[hibernate-core-5.6.4.Final.jar:5.6.4.Final]
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:1498) ~[hibernate-core-5.6.4.Final.jar:5.6.4.Final]
at org.springframework.orm.jpa.vendor.SpringHibernateJpaPersistenceProvider.createContainerEntityManagerFactory(SpringHibernateJpaPersistenceProvider.java:58) ~[spring-orm-5.3.15.jar:5.3.15]
at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:365) ~[spring-orm-5.3.15.jar:5.3.15]

Qual a relação entre as classes FechamentoCaixaItem e FechamentoCaixa. Imagino que a ideia seja que um fechamentoCaixa tenha uma lista de FechamentoCaixaItem, certo? Nesse caso, vc deve mapear o FechamentoCaixa na classe FechamentoCaixaItem para, qdo vc salvar, o ID do fechamentoCaixa seja gravado corretamente em cada item (isso tb faz parte do mapeamento que vc precisa fazer).