-3

I am working on a spring's stock management application. I have a function that create an invoice (facture), it create the invoice with the id of the customer (client), and in it I have an other function that create the invoice details. this is my entities:

the invoice entity:

@Entity
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@ToString
@EqualsAndHashCode
public class Facture implements Serializable {
    
    public Facture(float d, float e, Date date, boolean b, Set<DetailFacture> detailFactures2, Client c1) {
        // TODO Auto-generated constructor stub
    }

    /**
     * 
     */
    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue (strategy = GenerationType.IDENTITY)
    @Column(name="idFacture")
    private Long idFacture;
    @Column(name="montantRemise")
    private  float  montantRemise;
    @Column(name="montantFacture")
    private  float  montantFacture;
    @Temporal(TemporalType.DATE)
    @Column(name="dateFacture")
    private Date dateFacture;
    @Column(name="active")
    private boolean active;
    
    @OneToMany(mappedBy="facture")
    @JsonIgnore
    private Set<DetailFacture> detailFactures;
    
    @ManyToOne
    @JsonIgnore
    private Client client;
    
}

the invoice details entity:

@Entity
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@ToString
@EqualsAndHashCode
public class DetailFacture implements Serializable {
    
    /**
     * 
     */
    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue (strategy = GenerationType.IDENTITY)
    @Column(name="idDetailFacture")
    private Long idDetailFacture;
    @Column(name="qte")
    private  float  qte;
    @Column(name="prixTotal")
    private  float  prixTotal;
    @Column(name="pourcentageRemise")
    private int pourcentageRemise;
    @Column(name="montantRemise")
    private int montantRemise;
    
    @ManyToOne
    @JsonIgnore
    private Produit produit;
    
    @ManyToOne
    @JsonIgnore
    private Facture facture;

    
}

the customer entity:

@Entity
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@ToString
@EqualsAndHashCode
public class Client implements Serializable {
    
    /**
     * 
     */
    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue (strategy = GenerationType.IDENTITY)
    @Column(name="idClient")
    private Long idClient;
    @Column(name="nom")
    private String nom;
    @Column(name="prenom")
    private String prenom;
    @Temporal(TemporalType.DATE)
    @Column(name="dateNaissance")
    private Date dateNaissance;
    @Column(name="email")
    private String email;
    @Column(name="password")
    private String password;
    @Column(name="categorieClient")
    private CategorieClient categorieClient;
    @Column(name="profession")
    private Profession profession;
    
    @OneToMany(mappedBy="client")
    private List<Facture> factures;

    
}

this is my function in the invoice service that create an invoice with the customer id:

@Override
    @Transactional
    public Facture addFactureClient(Facture f, Long idClient) {
        // TODO Auto-generated method stub
        Client client = clientRepository.findById(idClient).orElse(null);
        f.setClient(client);
        f.setDateFacture(new Date());
        f.setActive(true);
        Set<DetailFacture> detailfactures = f.getDetailFactures();
        Facture facture = addDetailFacture(f, detailfactures);
        return factureRepository.save(facture);
    }

and this is the function that create the invoice details:

private Facture addDetailFacture(Facture f, Set<DetailFacture> detailfactures){
        float montantFacture = 0;
        float montantRemise = 0;
        System.out.println(detailfactures);
        for (DetailFacture detail : detailfactures){
            Produit produit = produitRepository.findById(detail.getProduit().getIdProduit()).orElse(null);
            float prixTotalDetail = detail.getQte() * produit.getPrixUnitaire();
            float montantRemiseDetail = (prixTotalDetail * detail.getPourcentageRemise())/100;
            float prixTotalDetailRemise = prixTotalDetail - montantRemiseDetail;
            detail.setMontantRemise((int)montantRemiseDetail);
            detail.setPrixTotal(prixTotalDetailRemise);
            montantFacture = montantFacture + prixTotalDetailRemise;
            montantRemise = montantRemise + montantRemiseDetail;
            detail.setProduit(produit);
            detail.setFacture(f);
            detailFactureRepository.save(detail);
        }
        f.setMontantFacture(montantFacture);
        f.setMontantRemise(montantRemise);
        return f;
    }

this is the function in my controller:

    @ApiOperation(value = "Ajouter facture avec client")
    @PostMapping("/add-facture/{idClient}")
    @ResponseBody
    Facture addFacture(@RequestBody Facture f, @PathVariable("idClient") long idClient) {
        return factureService.addFactureClient(f, idClient);
    }

this is how I am testing with postman: enter image description here

the problem is when I create a new invoice it returns a NullPointerException in this line :

Facture facture = addDetailFacture(f, detailfactures);

why detailfactures returns null?

Lajos Arpad
  • 64,414
  • 37
  • 100
  • 175
  • That line cannot cause a null pointer exception. A line inside the method `addDetailFacture` could, but not this call itself. Use a debugger and step through your code to check which variable is null. – knittl Dec 12 '21 at 13:32
  • Please add always the complete stacktrace. Without it is impossible to help – Jens Dec 12 '21 at 13:33
  • if guess `detailfactures` is null that's why `for (DetailFacture detail : detailfactures){` throws a `NullPointerException` – Jens Dec 12 '21 at 13:36
  • *why detailfactures returns null?* because it is not in your rquest structure – Jens Dec 12 '21 at 13:37
  • I change the request in postman like this: { "detailFactures":{ "qte": 3.0, "pourcentageRemise": 20, "produit":{ "idProduit":1 } } } but its the same problem – Khalil Fathalli Dec 12 '21 at 13:50

1 Answers1

0

This is the method you have a problem with

private Facture addDetailFacture(Facture f, Set<DetailFacture> detailfactures){
        float montantFacture = 0;
        float montantRemise = 0;
        System.out.println(detailfactures);
        for (DetailFacture detail : detailfactures){
            Produit produit = produitRepository.findById(detail.getProduit().getIdProduit()).orElse(null);
            float prixTotalDetail = detail.getQte() * produit.getPrixUnitaire();
            float montantRemiseDetail = (prixTotalDetail * detail.getPourcentageRemise())/100;
            float prixTotalDetailRemise = prixTotalDetail - montantRemiseDetail;
            detail.setMontantRemise((int)montantRemiseDetail);
            detail.setPrixTotal(prixTotalDetailRemise);
            montantFacture = montantFacture + prixTotalDetailRemise;
            montantRemise = montantRemise + montantRemiseDetail;
            detail.setProduit(produit);
            detail.setFacture(f);
            detailFactureRepository.save(detail);
        }
        f.setMontantFacture(montantFacture);
        f.setMontantRemise(montantRemise);
        return f;
    }

NPE (NullPointerException) happens when your code tries to refer a data member or call a method of an object that is null.

What could be null in your case:

  • detailfactures
  • produitRepository
  • detail
  • detail.getProduit()
  • produitRepository.findById(detail.getProduit().getIdProduit())
  • detail
  • produit
  • detail.getPourcentageRemise()
  • f

In order to find out what is null from these candidates, you will need to debug your application or look at the detailed error message to find out which line threw the null. Once that is found, you will know what is null and you will have the following options:

  • you can find out why it is null in the first place and fix the code chunk which originated the problem
  • you can try-catch and handle the null case with some special error-handling code
Lajos Arpad
  • 64,414
  • 37
  • 100
  • 175