1

I am seeing a unique situation where my keyset and key of a LinkedHashSet are containing different data types as shown below

enter image description here

As you can see that the key is a String and the keyset is a long.

Following code is failing because of that:

modifiedRowKeys.toArray(new Long[modifiedRowKeys.size()]);

I get ArrayStoreException for String values.

I was able to replicate this from Angular application where i am sending a Map<Long, Map<String,Object>> to my Spring server which contains the data as shared in the pic.

enter image description here

Edit 1:

Please see following strange behavior in eclipse:

enter image description here

Could it be an issue with Jackson Mapper which we are using for conversion of objects ?

Edit 2:

The following code fails with ClassCastException saying

String cannot be cast to Long

Set<Long> modifiedRowKeys = modifiedRowMap.keySet();
Long[] periodDateArray = new Long[modifiedRowKeys.size()];

int count = 0;
Iterator<Long> keyIterator = modifiedRowKeys.iterator();
while(keyIterator.hasNext()){
    Long key = keyIterator.next();
    System.out.println("key instanceof Long : " + (key instanceof Long));
    periodDateArray[count++] = Long.valueOf(key);
}

This seems pretty straight forward logic !

Edit 3:

I have recreated the problem as follows:

    public static void main(String[] args) {

        CollectionsToArray collectionsToArray = new CollectionsToArray();

        Map<String, Map<String, Object>> mapOfNumbers = collectionsToArray.prepareStrangeNumbersSetFromMapOfMap();

        Object obj = mapOfNumbers;
        collectionsToArray.convertMapToKeySetToArray(obj);

    }

    private Map<String, Map<String, Object>> prepareStrangeNumbersSetFromMapOfMap() {
        Map<String, Map<String, Object>> longNumberMap = new LinkedHashMap<>();

        Map<String, Object> stringValueMap = new HashMap<>();
        stringValueMap.put("Adams", "Adithya");
        stringValueMap.put("Edge", 80);

        longNumberMap.put("1488376800000", stringValueMap);

        return longNumberMap;
    }

    private void convertMapToKeySetToArray(Object obj) {
        Map<Long, Map<String, Object>> mapOfNumbers = (Map<Long, Map<String, Object>>) obj;
        Set<Long> stringNumbers = mapOfNumbers.keySet();

        convertLongKeySetToArray(stringNumbers);
    }

    private void convertLongKeySetToArray(Set<Long> stringNumbers) {
        Long[] stringNumbersArray = stringNumbers.toArray(new Long[0]);
        Arrays.sort(stringNumbersArray);

        System.out.println(stringNumbersArray);
    }
Adithya
  • 2,923
  • 5
  • 33
  • 47
  • 1
    Just to understand, you send an key,value list to a web page using long as key and then the page returns you back a list using a string as key? – freedev Jun 07 '17 at 08:46
  • 2
    Can you provide a [mcve]? Your explanation is unclear and you have not shown all your code... And please paste the code as text, not as an image. – assylias Jun 07 '17 at 08:55
  • 2
    And you need to put brakcets around `(key instanceof Long)` otherwise it won't compile. – assylias Jun 07 '17 at 08:56
  • 1
    I can tell about the "strange behavior" , use instead that line this: System.out.println("key instanceof Long:" + (key instanceof Long)); As you can see, the string was concatenated first with the value from key and then instanceof is not working between string and Long – Guilherme Jun 07 '17 at 08:58
  • my bad for not using the brakcets ! Thanks – Adithya Jun 07 '17 at 09:53
  • @assylias : Noted. – Adithya Jun 07 '17 at 10:09
  • 1
    You haven’t shown the declaration of `modifiedRowKeys`. Apparently, you are using a raw type somewhere and then insisting of using `Long` after the unchecked operation, despite everything tells you that the keys are `String`s. In the debugger screenshot, no `Long` is visible… – Holger Jun 07 '17 at 15:44

2 Answers2

2

If I run the code in your "Edit 2" with a Map<Long, String> it compiles and runs fine. So the problem is not in what you've shown so far. As said above, try to create a [mcve] that does reproduce the problem.

My best guess is that you have something like this:

Map m = new HashMap (); //raw map received from jackson
m.put("abc", "def"); //it's in fact a Map<String, String>
Map<Long, String> modifiedRowMap = m; //but you cast it to something else

The rest of the code will compile but you will get an exception at runtime.

assylias
  • 321,522
  • 82
  • 660
  • 783
  • Please refer Edit 3. – Adithya Jun 08 '17 at 07:09
  • @Adithya Well yes, you have a `Map` that you pass to a method as an `Object` and then you cast it to a `Map`. Note that the compiler gives you a warning about an unchecked cast. Why would you expect your code to work? – assylias Jun 08 '17 at 07:40
  • actually, i captured the javascript object into Map> in Spring server using jackson mapper. I didn't intend to do that :). To recreate i have added the Edit 3. – Adithya Jun 08 '17 at 12:08
  • I'm just saying that when you go from generics to raw type (Object in your case) to generic again, the compiler will emit a warning, assuming you know what you are doing. If the types don't match you get an exception and it's normal. Maybe the problem is where you parse the json input into an object with Jackson, but you haven't shown that code. You could try to create a small program where you have a hardcoded json input, map it with Jackson and reproduce the exception. – assylias Jun 08 '17 at 12:15
  • you are right about the warning and that warning should cause the following line to fail at runtime i believe Set stringNumbers = mapOfNumbers.keySet(); which doesn't. I will work on the sample program. – Adithya Jun 08 '17 at 14:56
  • @Adithya No it will work fine - it's only when you retrieve an element from the set and allocate it to a Long that you will get an exception. For example :`Long n = stringNumbers.iterator().next();` – assylias Jun 08 '17 at 16:26
  • Why will i get the exception when i retrieve an element from the set ? Why not when i create the Set ? Isn't it wrong that the set which is showing that it is storing long values isn't actually having long values ? – Adithya Jun 14 '17 at 07:29
  • 1
    @Adithya I don't know if it's right or wrong, but it's how the Java language specification have been written. Raw types are only there for backward compatibility and shouldn't be used lightly. See also: https://stackoverflow.com/a/2770692/829571. – assylias Jun 14 '17 at 08:25
  • Thanks for your replies. Appreciate your help ! – Adithya Jun 14 '17 at 11:11
1

You are confusing something, that key is a String, but keySet is actually a Set that uses toString to show the output with [].

 Set<String> set = new HashSet<>();
 set.add("1");
 set.add("2");
 System.out.println(set); // [1, 2]

So you have a String and a Set (not a long).

And this fails because String is known to not be a Long at compile-time, no runtime check is needed (also add the missing parentheses):

System.out.println("key instanceof Long" + (s instanceof Long));
Eugene
  • 117,005
  • 15
  • 201
  • 306
  • If it was Set i would understand; question is why is it a Set ? Why does the code Set keys = modifiedRowMap.keySet(); compile ? It should compile for Set right ? – Adithya Jun 07 '17 at 10:20