views:

30

answers:

1

Hey,

I'm trying to accommodate to Spring JDBC, but what bugs me is using these anonymous classes, where we cannot pass any local variables unless they are final which might be easy to arrange, but what about if I need to loop an array or collection ? I cannot declare "FedModel fm" to be final as it gets reinitialized in the loop, but I need to call the execute method 100 times. This is concrete scenario where I have the problem, cause I don't know any other way how to insert BLOB into a database.

 for (int i = 0; i < fedModels.size(); i++) {
        FedModel fm = fedModels.get(i);

        jdbcTemplate.execute("INSERT INTO items (name, video_blob) VALUES (?, ?)",
                  new AbstractLobCreatingPreparedStatementCallback(lobHandler) {
                  protected void setValues(PreparedStatement ps, LobCreator lobCreator) 
                        throws SQLException {
                            ps.setString(1, fm.getName());
                            ps.setString(2, fm.getDifficultyLevel());
                            ps.setString(3, fm.getEquipment());
                            lobCreator.setBlobAsBinaryStream(ps, paramIndex, contentStream, contentLength);                                                     
                          }
                });

} 

The only thing I can think of, is creating a static Nested class that extends AbstractLobCreatingPreparedStatementCallback and adds constructor for fedModels so that I could do the loop inside. But it would be easier using only JDBC.

+1  A: 

... but what bugs me is using these anonymous classes, where we cannot pass any local variables unless they are final ...

This is not Spring's fault. It is property of the Java programming language.

Basically, the Java language (at least Java 6 and earlier) does not support closures which would allow the anonymous class instance to access and update local variables in the instance's enclosing scopes. As a workaround, the language allows you to access enclosing local variables that are final. This is implemented (without closures) by copying the respective variable's values into the anonymous class instance, and storing them in hidden variables.

In your particular case, the simple solution is to declare fm as final. If you needed to access the loop variable in the anonymous class, you could declare a final copy; e.g.

for (int i = 0; i < 10; i++) {
    final int ii = i;
    new Thread(new Runnable(){
        public void run() {
            System.err.println(ii);
        }
    }).start();
}
Stephen C
@Stephen, if a final variable is assigned a reference to an object, it will always refer to the same object. If it is assigned a primitive value, it may be done so only once and the value cannot be changed. How do you think I can declare "FedModel fm" variable and "i" variable final, if they both are assigned 100 times ?
lisak
@Stephen, sorry I though that the variables declared inside the for loop would get reassigned 100 times, but I just tried and it works, because within the 1 cycle of the for loop they get initialized once but recreated in the second cycle, right ?
lisak
@lisak - that is correct.
Stephen C