2

I am using JPA and I have an entity/class named Order. I have a rest GET endpoint to fetch an order by an id. It works perfectly fine. The order entity looks like below:

@Entity
public class Order {

@Id
private Long id;

@Column
private List<String> transactionRefs;
}

Now, in one particular scenario, I need to fetch the order from the database and add another item to the transactionRefs and save it. So I do as below:

Order order = orderRepository.findById(1).get();
List<String> transactionList = order.getTransactionRefs();
transactionList.add("transaction-ref");

I get the below error when I do that:

java.lang.UnsupportedOperationException: null\n\tat java.util.AbstractList.add(AbstractList.java:148)

If I do as below, that fixes the problem:

Order order = orderRepository.findById(1).get();
List<String> transactionList = order.getTransactionRefs();
transactionList = new ArrayList<>(transactionList);
transactionList.add("transaction-ref");

So, I need to know if I am in the right direction here and is this an expected error scenario.

Update:

Whenever we are adding an item to the list, we have the below condition :

if (transactionRefs == null) {
        transactionRefs = new ArrayList<>();
}

So, whenever the transactionref is saved for the first time, we cast it to a ArrayList.

Update 2 :

Below is the getter for the transactionRef:

public List<String> getTransactionRefs(){
    if (this.transactionRefs != null) {
        return Arrays.asList(this.transactionRefs.split(","));
    }
    return null;
}
T Anna
  • 874
  • 5
  • 21
  • 52
  • Looks like the right thing to do to me. Some methods of the List-Interface are documented as "optional operation" including the add method - this allows special types of lists to be read-only implementations. When receiving a List there is always the chance it is unmodifiable. Creating a new ArrayList to work on is the safe way to do it. – Roland Kreuzer Jun 29 '20 at 10:50
  • "... and add another item to it and **save** it", what makes me wonder is, why are you fetching the entire collection to save a single new record? It's way too inefficient and not scalable at all. I am sure you know that saving that single record without fetching entire collections is the best way. Am I missing something here? – Avnish Jun 29 '20 at 10:52
  • @Avnish I have updated my question to reflect the actual scenario. Please let me know if that makes sense. – T Anna Jun 29 '20 at 11:02
  • Do you have a converter or a tokenizer associated with that List annotation? How is the List getting produced? – Joe W Jun 29 '20 at 11:05
  • @JoeW I have edited the question and mentioned an update. Could you please take a look. So, to summarize, whenever am item was added in it for the first time, iwe are using an ArrayList. – T Anna Jun 29 '20 at 11:09
  • I'm asking more about the annotation for \@Column returning a list. You have to provide a converter or \@ElementCollection annotation for that to work. Database columns can't directly return a collection to you. There is logic somewhere that is returning an immutable list to you probably via Arrays.asList() – Joe W Jun 29 '20 at 11:13
  • @JoeW Ah i see, I have found something and made another update in the question. Does that answer your question? – T Anna Jun 29 '20 at 11:19

1 Answers1

2

This is the cause of your exception

return Arrays.asList(this.transactionRefs.split(","));

Arrays.asList returns a collection backed by the array and it can't be modified with add or addAll. You need to create the List just like you are doing in the question:

List<String> transactionList = order.getTransactionRefs();
transactionList = new ArrayList<>(transactionList);

For more examples:

Joe W
  • 2,773
  • 15
  • 35