1

I am working on Spring Data JPA + Postgres lombok example. In this example I am getting below error.

java.lang.IllegalStateException: Failed to execute CommandLineRunner
    at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:782) [spring-boot-2.1.6.RELEASE.jar:2.1.6.RELEASE]
    at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:763) [spring-boot-2.1.6.RELEASE.jar:2.1.6.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:318) [spring-boot-2.1.6.RELEASE.jar:2.1.6.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1213) [spring-boot-2.1.6.RELEASE.jar:2.1.6.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1202) [spring-boot-2.1.6.RELEASE.jar:2.1.6.RELEASE]
    at org.example.StockApplication.main(StockApplication.java:18) [classes/:na]
Caused by: java.lang.UnsupportedOperationException: null
    at java.util.AbstractCollection.add(AbstractCollection.java:262) ~[na:1.8.0_171]
    at org.hibernate.collection.internal.PersistentSet.add(PersistentSet.java:211) ~[hibernate-core-5.3.10.Final.jar:5.3.10.Final]
    at org.example.StockApplication.run(StockApplication.java:40) [classes/:na]
    at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:779) [spring-boot-2.1.6.RELEASE.jar:2.1.6.RELEASE]
    ... 5 common frames omitted

Stock.java

@Builder
@Getter
@AllArgsConstructor
@Entity
@Table(name = "stock", catalog = "mkyongdb", uniqueConstraints = { @UniqueConstraint(columnNames = "STOCK_NAME"),
        @UniqueConstraint(columnNames = "STOCK_CODE") })
public class Stock implements java.io.Serializable {
    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = IDENTITY)
    @Column(name = "STOCK_ID", unique = true, nullable = false)
    private Integer stockId;

    @Column(name = "STOCK_CODE", unique = true, nullable = false, length = 10)
    private String stockCode;

    @Column(name = "STOCK_NAME", unique = true, nullable = false, length = 20)
    private String stockName;


    @Singular
    @OneToMany(fetch = FetchType.LAZY, mappedBy = "stock")
    private final Set<StockDailyRecord> stockDailyRecords;
}

StockDailyRecord.java

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Entity
@Table(name = "stock_daily_record", catalog = "mkyongdb", uniqueConstraints = @UniqueConstraint(columnNames = "DATE"))
public class StockDailyRecord implements java.io.Serializable {

    @Id
    @GeneratedValue(strategy = IDENTITY)
    @Column(name = "RECORD_ID", unique = true, nullable = false)
    private Integer recordId;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "STOCK_ID", nullable = false)
    private Stock stock;

    @Column(name = "PRICE_OPEN", precision = 6)
    private Float priceOpen;

    @Column(name = "PRICE_CLOSE", precision = 6)
    private Float priceClose;

    @Column(name = "PRICE_CHANGE", precision = 6)
    private Float priceChange;

    @Column(name = "VOLUME")
    private Long volume;

    @Temporal(TemporalType.DATE)
    @Column(name = "DATE", unique = true, nullable = false, length = 10)
    private Date date;
}

Main.App

@SpringBootApplication
public class StockApplication implements CommandLineRunner{

    public static void main(String[] args) {
        SpringApplication.run(StockApplication.class, args);
    }

    @Autowired
    private StockRepository stockRepository;
    @Autowired
    private StockDailyRecordRepository stockDailyRecordRepository;

    @Override
    public void run(String... args) throws Exception {
        Stock stock = Stock.builder().stockCode("7052").stockName("PADINI").build();
        stockRepository.save(stock);

        StockDailyRecord stockDailyRecords = StockDailyRecord.builder()
                .priceOpen(new Float("1.2"))
                .priceChange(new Float("10.0"))
                .priceClose(new Float("1.1"))
                .date(new Date())
                .volume(3000000L)
                .build();

        stockDailyRecords.setStock(stock);        
        stock.getStockDailyRecords().add(stockDailyRecords); //Line-22
        stockDailyRecordRepository.save(stockDailyRecords);
    }
}

Note: Code is breaking at line-22

PAA
  • 1
  • 46
  • 174
  • 282

2 Answers2

2

Read the @Singular part at https://projectlombok.org/features/Builder and you should have your answer.

Basically after invoking build() the underlying collection will be immutable thus not allowing adding any more data. A proper way would be to reuse the builder, add new stockDailRecords and create a new object.

Unfortunately in your case it would probably break the persistence part since the database expects the same object to be modified. IMO using such immutable objects for this task is not wise at all.

Also a very similar question has already been discussed at UnsupportedOperationException is thrown with Lombok Builder annotation

käyrätorvi
  • 371
  • 1
  • 9
  • It still not working .. Getting Below error `Caused by: org.hibernate.PropertyValueException: not-null property references a null or transient value : org.example.model.StockDailyRecord.stock at org.hibernate.engine.internal.Nullability.checkNullability(Nullability.java:108) ~[hibernate-core-5.3.10.Final.jar:5.3.10.Final]` – PAA Jul 01 '19 at 08:01
1

In line 22 stockDailyRecords set can be null. Do a check before adding values.

if(Objects.nonNull(stock.getStockDailyRecords())){
    stock.getStockDailyRecords().add(stockDailyRecords);
} else {
    Set setA = new HashSet();
    set.add(stockDailyRecords);
    stock.setStockDailyRecords(setA);
}
Vimukthi
  • 846
  • 6
  • 19
  • How does this help? Upon invoking *build()* Lombok will produce an empty immutable collection as the *stockDailyRecords* set so this check never goes to the second branch. – käyrätorvi Jul 01 '19 at 08:47