33

I am getting an ArrayIndexOutOfBoundsException on service start up (Bean creation) when i use Java 8 features.

Java 8 has been set up and has been working. The code compiles correctly. On service start, the service fails to listen to port as the beans don't get created. When i change the code (remove java 8 constructs) the service starts and everything works fine.

This is the code i am using (the working code for which the service starts):

for (Item itemObject : response) {
    if (itemObject.hasId()) {
        idList.add(String.valueOf(itemObject.Id());
    }
}

Same code using Java 8 constructs:

response.parallelStream()
        .filter(itemObject -> itemObject.hasId())
        .map(itemObject -> itemObject.getId())
        .forEach(id -> idList.add(id));

The bean for the class containing this piece of code is created using component scan.

The following is the exception message when the second code block is used in place of the first one:

Exiting with throwable: java.lang.IllegalArgumentException: org.springframework.beans.factory.BeanDefinitionStoreException: Failed to read candidate component class: URL [jar:file:/workspace/.../GetContainerIdForFcSkuAdapter.class]; nested exception is java.lang.ArrayIndexOutOfBoundsException: 51880
 java.lang.IllegalArgumentException: org.springframework.beans.factory.BeanDefinitionStoreException: Failed to read candidate component class: URL [jar:file:/workspace....Some.class]; nested exception is java.lang.ArrayIndexOutOfBoundsException: 51880

What does not make sense to me is, why is the code inside a function (which is not the constructor of the bean class) being covered while creating the bean. I ask this, because the exception is not there when i use the normal for loop instead of the parallel stream. Shouldn't an ArrayOutOfBoundsException arise when the function is called and this code is actually used.

How do i fix this?

xenteros
  • 15,586
  • 12
  • 56
  • 91
akshitBhatia
  • 1,131
  • 5
  • 12
  • 20
  • 2
    What is `idList`? In the second version you are using `parallelStream` so you are adding items to this list from multiple threads. Is the list implementation that you use thread-safe? Does the error disappear if you use `stream()` instead of `parallelStream()`? – Jesper Jun 09 '15 at 10:15
  • 2
    Also, the normal way to get the content of a stream in a list is `List list = stream.collect(Collectors.toList())` instead of `stream.forEach(o -> list.add(o)`. – Jesper Jun 09 '15 at 10:18
  • i am not adding from multiple threads really. Java is internally unrollling the loop and parallelizing. error still exists on using steam. Like i said, the block of code should be executed when the function is called, not on bean creation. How is this block getting used and giving ArrayIndexOutOfBounds on service start up. Please look at my answer below and tell me if you think that could be a reason – akshitBhatia Jun 09 '15 at 10:28

2 Answers2

63

Which version of Spring do you use? You need upgrade to Spring 4 to use Java 8 lambda expressions.

vasekt
  • 2,055
  • 2
  • 17
  • 13
  • 1
    Yes, 4.0.X.RELEASE working with java 8. – Buminda Jan 01 '16 at 21:10
  • 4.0 does not suffice. It needs to be at least ***4.0.4*** or higher. The bug is described [here](https://github.com/spring-projects/spring-framework/issues/16341) as Issue 16341 – Lonzak Mar 19 '20 at 17:23
23

I found a bug recently when using Spring 3.0.5, which appears to be fixed in 4.0.5. Here are the details.

If you have a class that has a parameterized constructor and also has a method that uses a lambda expression (introduced in Java 8), then a ArrayIndexOutOfException occurs when creating a bean for that class.

Ash
  • 1,210
  • 1
  • 10
  • 14
  • 4
    This is not really a bug. Spring 3 does not completely support Java 8, so using Lambdas with Spring 3.0.5 is a user error and not a Spring bug. – stefan.m Oct 17 '16 at 08:44
  • 6
    I just ran into this and it seemed awfully strange. It happened as you say, when I added a parameter to the bean's constructor. I was using forEach in a couple of places. I don't think I would have ever made this connection that a forEach anywhere in the class would break its bean instantiation with an array bounds exception. Oh well -- thanks, Stack Overflow! – botimer Nov 15 '16 at 23:18
  • 7
    you cleared me away from a nightmarish headache ! Thanks ! – Guillaume Jan 03 '17 at 13:13
  • 1
    I faced the same issue but the case is bit different. My class does not have any parameterized constructor but uses lambda expression in one function. I tried upgrading spring to v4 that didn't help. Removing the lambda expression did work though. It is a weird issue! Can anyone explain why this is happening exactly? – Shubham May 12 '20 at 08:45