2

I tryed to iterate a springframework.LinkedMultiValueMap, using:

  • iterator
  • foreach
  • stream.foreach
  • while
  • collections.values().foreach
  • sudoku(kidding)

But successively gets the error: cannot be cast to class

Here is the code:

package com.br.aloi.planner.controller;

import java.io.IOException;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;

import javax.validation.Valid;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;

import com.br.aloi.planner.model.CSVModel;
import com.br.aloi.planner.model.CSVModelAttributes;
import com.br.aloi.planner.service.CSVService;
import com.br.aloi.planner.service.MapsApiService;
import com.google.gson.Gson;
import com.google.gson.JsonParser;
import com.google.maps.errors.ApiException;

@Controller
public class CustomerController {

  String query;
  @Autowired
  private CSVService CSVservice;

  @GetMapping("/planner")
  public ModelAndView getPlanner(
        @RequestParam(value = "sortBy", defaultValue = "id", required = false) String sortParam,
        @RequestParam(value = "action", required = false) Optional<String> action)
        throws ApiException, InterruptedException, IOException {
     ModelAndView mv = new ModelAndView("/planner");
     Optional<CSVModel> csvModel = CSVservice.findById(0); //0 is just for test the linkedvaluemap

     /* this is the linkedvaluemap. Created converting a 
     "json linkedvaluemap string" to a linkedvaluemap, with gson's help. */
     @SuppressWarnings("unchecked")
     final LinkedMultiValueMap<Integer, CSVModelAttributes> attrib = new Gson().fromJson(
          (csvModel.get().getAttributes()), LinkedMultiValueMap.class);

     /* HERE i create a collection only with the values of each entry
     of linkedvaluemap. the values are a list of CSVModelAttributes */
     Collection<List<CSVModelAttributes>> valuesOfAttrib = attrib.values();

     /* HERE i run each one collections values to get the list of 
     CSVModelAttribues and after get the attribute getValue() of each model */
     for (List<CSVModelAttributes> value : valuesOfAttrib) {
        int i = 0;
        while (i < value.size()) {
          query += value.get(i).getValue() + "+";
          i++;
        }
        System.out.println(query);
        System.out.println(MapsApiService.getLat(query));
     }
     mv.addObject("csvModels", CSVservice.sortBy(csvModels, sortParam));
     return mv;

  }
}

THE CSVModelAttributes class

package com.br.aloi.planner.model;

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

import com.google.gson.Gson;

@SuppressWarnings("serial")
@Entity(name = "tbl_modelAttributes")
public class CSVModelAttributes implements Serializable {

  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Integer id;
  @Column
  private Integer modelId;
  @Column(columnDefinition = "TEXT")
  private String key;
  @Column(columnDefinition = "TEXT")
  private String value;

  public CSVModelAttributes() {
  }

  public CSVModelAttributes(String key, String value) {
     this.modelId = modelId;
     this.key = key;
     this.value = value;
  }

  public Integer getId() {
     return id;
  }

  public void setId(Integer id) {
     this.id = id;
  }

  public Integer getModelId() {
     return modelId;
  }

  public void setModelId(Integer modelId) {
     this.modelId = modelId;
  }

  public String getKey() {
     return key;
  }

  public void setKey(String key) {
     this.key = key;
  }

  public String getValue() {
     return value;
  }

  public void setValue(String value) {
     this.value = value;
  }

  @Override
  public String toString() {
     return new Gson().toJson(this);
  }

}

THE CSVModel class

package com.br.aloi.planner.model;

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.validation.constraints.Size;

import lombok.AllArgsConstructor;

@SuppressWarnings("serial")
@Entity(name = "tbl_csv")
@AllArgsConstructor
public class CSVModel implements Serializable {
  @Id
  private Integer id;
  @Column(length = 1024)
  @Size(max = 1024)
  private String attributes;

  public CSVModel() {

  }

  public Integer getId() {
     return id;
  }

  public Integer setId(Integer id) {
     return this.id = id;
  }

  public String getAttributes() {
     return attributes;
  }

  public void setAttributes(String attributes) {
     this.attributes = attributes;
  }

}

THE ERROR:

java.lang.ClassCastException: class com.google.gson.internal.LinkedTreeMap cannot be cast to class com.br.aloi.planner.model.CSVModelAttributes (com.google.gson.internal.LinkedTreeMap and com.br.aloi.planner.model.CSVModelAttributes are in unnamed module of loader 'app')
    at com.br.aloi.planner.controller.CustomerController.getPlanner(CustomerController.java:63) ~[classes/:na]
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na]
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
    at java.base/java.lang.reflect.Method.invoke(Method.java:564) ~[na:na]
    at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190) ~[spring-web-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138) ~[spring-web-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:105) ~[spring-webmvc-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:879) ~[spring-webmvc-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:793) ~[spring-webmvc-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040) ~[spring-webmvc-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943) ~[spring-webmvc-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) ~[spring-webmvc-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898) ~[spring-webmvc-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:634) ~[tomcat-embed-core-9.0.36.jar:9.0.36]
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883) ~[spring-webmvc-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:741) ~[tomcat-embed-core-9.0.36.jar:9.0.36]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) ~[tomcat-embed-core-9.0.36.jar:9.0.36]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.36.jar:9.0.36]
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) ~[tomcat-embed-websocket-9.0.36.jar:9.0.36]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.36.jar:9.0.36]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.36.jar:9.0.36]
    at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) ~[spring-web-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.36.jar:9.0.36]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.36.jar:9.0.36]
    at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) ~[spring-web-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.36.jar:9.0.36]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.36.jar:9.0.36]
    at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) ~[spring-web-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.36.jar:9.0.36]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.36.jar:9.0.36]
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202) ~[tomcat-embed-core-9.0.36.jar:9.0.36]
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) ~[tomcat-embed-core-9.0.36.jar:9.0.36]
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541) ~[tomcat-embed-core-9.0.36.jar:9.0.36]
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139) ~[tomcat-embed-core-9.0.36.jar:9.0.36]
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) ~[tomcat-embed-core-9.0.36.jar:9.0.36]
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74) ~[tomcat-embed-core-9.0.36.jar:9.0.36]
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343) ~[tomcat-embed-core-9.0.36.jar:9.0.36]
    at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:373) ~[tomcat-embed-core-9.0.36.jar:9.0.36]
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) ~[tomcat-embed-core-9.0.36.jar:9.0.36]
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868) ~[tomcat-embed-core-9.0.36.jar:9.0.36]
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1590) ~[tomcat-embed-core-9.0.36.jar:9.0.36]
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) ~[tomcat-embed-core-9.0.36.jar:9.0.36]
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1130) ~[na:na]
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:630) ~[na:na]
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) ~[tomcat-embed-core-9.0.36.jar:9.0.36]
    at java.base/java.lang.Thread.run(Thread.java:832) ~[na:na]

THE JSON STRING

{0=[{"key":"customerId","value":"4891"}, {"key":"companyName","value":"GIOVANE FERREIRA"}, {"key":"place","value":"AV  AV TEPEQUEM                   SN"}, {"key":"neighborhood","value":"CENTRO"}, {"key":"city","value":"AMAJARI"}, {"key":"a","value":"RR"}, {"key":"postalCode","value":"69300000"}, {"key":"c","value":"ISENTO"}, {"key":"tradeName","value":"CIA DO GELO"}, {"key":"sectorId","value":"301"}, {"key":"region","value":"RR"}]}

2 days on without solution, i'm almost getting rid of this library and putting the apache commons collection.

3 Answers3

1
@SuppressWarnings("unchecked")
     final LinkedMultiValueMap<Integer, CSVModelAttributes> attrib = new Gson().fromJson(
          (csvModel.get().getAttributes()), LinkedMultiValueMap.class);

This line has a problem.

{0=[{"key":"customerId","value":"4891"}, {"key":"companyName","value":"GIOVANE FERREIRA"}, {"key":"place","value":"AV  AV TEPEQUEM                   SN"}, {"key":"neighborhood","value":"CENTRO"}, {"key":"city","value":"AMAJARI"}, {"key":"a","value":"RR"}, {"key":"postalCode","value":"69300000"}, {"key":"c","value":"ISENTO"}, {"key":"tradeName","value":"CIA DO GELO"}, {"key":"sectorId","value":"301"}, {"key":"region","value":"RR"}]}

The deserialized message has different data types then you're trying to typecast.

LinkedMultiValueMap<Integer, Object> linkedHashMap = (LinkedMultiValueMap<Integer, Object>)(new Gson().fromJson(json,LinkedMultiValueMap.class));
    for(Entry<Integer, List<Object>> entry: linkedHashMap.entrySet()){
      System.out.println(entry.getValue().get(0).getClass());
    }

This code would print class com.google.gson.internal.LinkedTreeMap, this clearly says the data type in the list is something else, that's not CSVModelAttributes, in fact, it's a list of TreeMap.

You should define a model like this

public class CsvModels extends LinkedMultiValueMap<Integer, CSVModelAttributes> {}

Usage:

 String json =
        "{0=[{\"key\":\"customerId\",\"value\":\"4891\"}, {\"key\":\"companyName\",\"value\":\"GIOVANE FERREIRA\"}, {\"key\":\"place\",\"value\":\"AV  AV TEPEQUEM                   SN\"}, {\"key\":\"neighborhood\",\"value\":\"CENTRO\"}, {\"key\":\"city\",\"value\":\"AMAJARI\"}, {\"key\":\"a\",\"value\":\"RR\"}, {\"key\":\"postalCode\",\"value\":\"69300000\"}, {\"key\":\"c\",\"value\":\"ISENTO\"}, {\"key\":\"tradeName\",\"value\":\"CIA DO GELO\"}, {\"key\":\"sectorId\",\"value\":\"301\"}, {\"key\":\"region\",\"value\":\"RR\"}]}";
    CsvModels models = (new Gson().fromJson(json, CsvModels.class));
    for (Entry<Integer, List<CSVModelAttributes>> entry : models.entrySet()) {
      System.out.println(entry.getKey());
      for (CSVModelAttributes attributes : entry.getValue()) {
        System.out.println("\t" + attributes);
      }
    }
sonus21
  • 5,178
  • 2
  • 23
  • 48
1

I tried running your code using Junits.

enter image description here

And it shows perfectly fine results.

enter image description here

So Now I see two possible issues.

  1. The Gson version you are using might have some problems.
  2. The String that you get from the entity might be incorrect.

Can you please check both of those things?

Anand Vaidya
  • 1,374
  • 11
  • 26
1

This is the problematic line:

final LinkedMultiValueMap<Integer, CSVModelAttributes> attrib = new Gson().fromJson(
      (csvModel.get().getAttributes()), LinkedMultiValueMap.class);

Gson doesn't known in what class-type you want your values. It just known it needs to make a LinkedMultiValueMap. Try something like:

Type mapType = new TypeToken<LinkedMultiValueMap<Integer, CSVModelAttributes>>(){}.getType();
attrib = new Gson().fromJson(csvModel.get().getAttributes()), mapType );

See here also

Eelco
  • 69
  • 4