Search code examples
javaspringjvmibatisibatis.net

Java valueOf(int) with IntegerCache returns value 3 for valueOf(1)


I am facing problem with IntegerCache : Using iBatis data access framework which internally use iBatis PreparedStatement class.

Calling database procedure like

{ call UPDATE_PROC(?,?,?,?,?,?)  }
with params : [123, 234, 345, TEST1, 567, TEST2]

while iBatis API setting first parameter using :

typeHandler.setParameter(ps, i + 1, value, mapping.getJdbcTypeName());

i=0, value=123

here ps is reference to PreparedStatement, i is parameter index in database procedure.

it internally call

 ps.setInt(i, ((Integer) parameter).intValue());

i=1, parameter=123 (Note : i is int not Integer)

Internally this call invoked using Java reflection api :

public Object invoke(Object proxy, Method method, Object[] params) throws Throwable

method : setInt, params : [1, 123]

while getting Integer value of i for method invocation, JVM invoke below method :

public static Integer valueOf(int i) {
    assert IntegerCache.high >= 127;
    if (i >= IntegerCache.low && i <= IntegerCache.high)
        return IntegerCache.cache[i + (-IntegerCache.low)];
    return new Integer(i);
}

IntegerCache.low = -128 IntegerCache.high = 127

the value of IntegerCache.cache[i + (-IntegerCache.low)] ends up with IntegerCache.cache[129] there should be value 1 at integer cache index [129] but when I debug the code i found value 3 at index [129] :

, -8, -7, -6, -5, -4, -3, -2, -1, 0, 3 **index[129]**, 2, 3 **index[131]**, 4, 5, 6, 7, 8, 9, 10, 11

as IntegerCache is final type there should not be repeating values e.g. 3 at index [129] and [131]

so, I end up with exception :

java.sql.SQLException: Missing IN or OUT parameter at index:: 1

my question is how this can be possible? please suggest


Solution

  • Yes you are right. Got solution for this. I think there is a problem with STS JVM debug mode. When we change the value of primitive int property of Integer type of instance it override IntegerCache value.

    This should not happen as when next time when we request for same value it gives overridden value.

    done small POC using below code with normal and debug mode and able to reproduce the issue :

    public class TestEclipseJVMDebugger {
    
        public static void main(String[] argc) {
    
            Integer i1 = new Integer(27);
            int i2 = 7;
    
            assert (-128 <= i1 && i1 <= 127);
            assert (-128 <= i2 && i2 <= 127);
    
            System.out.println("i1 = " + i1);
            i1 = Integer.valueOf(i2);
            System.out.println("i1 = " + i1);
    
            System.out
                    .println("apply debug point here and change value of primitive data type of i1 to 666 from debug mode");
            System.out.println("i1 = " + i1);
            i1 = Integer.valueOf(i2);
            System.out.println("i1 = " + i1);
    
        }
    
    }
    

    I do not know why Eclipse JVM debug mode allow to update primitive datatype values directly as they directly overwrite reference value of core JVM classes.

    then I think same issue with StringCache, DoubleCache etc. too.