0

In my Spring Boot Project I have two classes (Entity and Model)

In the model there is a List<List<Object>>:

public class FCSeriesModel {
    private String name;
    private List<List<Object>> values;
    //GET & SET 
}

In the entity there is a List<List<String>> (because I can't use a List<List<Object>>):

    @Entity
    @Table(name = "Final_Feign_Client_Result")
    public class FinalFCResultEntity {
    
        @Id
        @Column(name = "id")
        @GeneratedValue(strategy = IDENTITY)
        private Integer id;
    
        @Column(name = "name")
        private String name;
    
        @ElementCollection
        @CollectionTable(name = "Final_Feign_Client_Result_Columns")
        @OnDelete(action = OnDeleteAction.CASCADE)
        @JoinColumn(name = "final_feign_client_result_entity_id", nullable = false)
        protected List<List<String>> values;
    
        // GET & SET
        }

How to convert the List<List<Object>> to List<List<String>> in a method of a service class to post the values of the model in the db?

    @Transactional
    public FinalFCResultEntity postFinalFCResultEntity() throws Exception {
        final String methodName = "getAllMonterotondoMarittimoModelPstgrs()";
        try {
            this.startLog(methodName);
            String token = getToken();
            FinalFCResultModel FFCRM = feignClient.getAllObject(token);
            logger.info("Request Successful");
            logger.info("FeignClientResultModel:" + FFCRM.toString());

            List<FCResultModel> FCRMs = FFCRM.getResults();
            FinalFCResultEntity FFCRE = new FinalFCResultEntity();

            if (!FCRMs.isEmpty()) {
                for (FCResultModel currFCRM : FCRMs) {
                    for (FCSeriesModel currFCSM : currFCRM.getSeries()) {
                        FFCRE.setName(currFCSM.getName());  

                        //ADD setting FFCRE values?????

                        FinalFCResultEntity FFCREsaved = finalFCResultDao.save(FFCRE);
                    }
                }
            }
            this.endLog(methodName, FFCRE);
            return FFCRE;
        } catch (final Exception e) {
            logger.error(e.getMessage());
            this.errorLog(methodName, e);
            throw e;
        }
    } 

2 Answers 2

2

This depends entirely on one thing: Are the elements in the List<List<Object>> all List<String>? If you know that they are, you can cast.

    @Test
    public void checkCasting() {
        List<List<Object>> objects = Arrays.asList(
                Arrays.asList("This", "is", "an", "example"),
                Arrays.asList("of", "a", "list", "of", "list"),
                Arrays.asList("of", "strings", "and", "no", "other", "things"));

        @SuppressWarnings({"unchecked", "rawtypes"})
        List<List<String>> stringlist = (List<List<String>>) (List) objects;
        Assertions.assertEquals(objects, stringlist);
    }

Now, this is dirt nasty. You can't convert directly to List<List<String>> so you cast to a raw list first, and then you convert to your list of list of string. This is only safe if you 100% absolutely know that there is not, and will never ever be any non-string entities in that list. The conversion will not check for you. It will fail silently at runtime. But you can't be too sure when it will fail.

So, if you can't guarantee that, you'll need to convert them. The best way to do that is to create something that converts a List<Object> to List<String>, and call that method on every list. Something like:

List<String> convertToStringList(List<Object> objects) {
  List<String> out = new ArrayList<>();
  for(Object o : objects) {
    out.add(o.toString()); // or something more precise
  }
  return out;
}

List<List<String> convertToNestedListOfString(List<List<Object>> objectLists) {
 List<List<String>> out = new ArrayList<>();
 for(List<Object> objectList : objectLists) {
    out.add(convertToStringList(objectList));
 }
 return out;
}

Easy peasy, lemon squeezy. Remember that String's toString method just returns itself so it's a trivial operation for strings. But if you want it to fail if the object is not a String, cast to String instead. Or check if the members of the inner lists are instanceof String, and throw your own exception if that's the case. Up to you. You still have to create new lists, so this will be slower than the naive cast-casting, but at least you know what you're getting. I'd go with the second option every time, because quite frankly code that runs fast but gives me the wrong result (or blows up an hour later) isn't very useful to me in my setting, and I could never give the strong guarantees needed for the cast-casting variation.

Sign up to request clarification or add additional context in comments.

Comments

2

In addition to @Haakon Løtveit's answer. More elegant way using Java 8+ Stream API:

List<List<Object>> objects = ...

List<List<String>> stringlist = objects.stream()
                .map(it -> it.stream().map(Object::toString).collect(Collectors.toList()))
                .collect(Collectors.toList());

2 Comments

Wouldn't it be better to just do objects.stream().map(this::convertToStringList).collect(toList())?
@HaakonLøtveit it would require method convertToStringList to be declared. I don't have in my code snippet

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.