2016-05-06 5 views
0

Ein seltsames NullPointer während der Verwendung von jdbcTemplate hält mich ab und ich kann den Ursprung der NullPointerException nicht finden.Seltsame Nullzeiger mit jdbcTemplate

Quelle Snippet:

@Slf4j 
public class ApproximationBuilder { 

    // [...] 

    public static DistributionApproximation buildQuadraticApproximation(JdbcOperations jdbcTemplate, String table, String column) { 
    int id_min = jdbcTemplate.queryForObject("SELECT MIN(" + column + ") from " + table + " WHERE " + column + " IS NOT NULL", Integer.class); 
    int id_max = jdbcTemplate.queryForObject("SELECT MAX(" + column + ") from " + table + " WHERE " + column + " IS NOT NULL", Integer.class); 
    int id_half = 0; 

    try { 
     id_half = jdbcTemplate.queryForObject("SELECT MAX(" + column + ") from " + table + " WHERE " + column + " IS NOT NULL " + " and " + column + " < " + Math.ceil((id_max - id_min)/2.0), Integer.class); 
     // The above line is number 36 
    } catch (NullPointerException e) { 
     // THIS SHOULD NOT HAPPEN! 
     log.error("Null Pointer! " + e.getMessage()); 
     id_half = (id_max - id_min)/2; 
    } 

    // ... 
} 

Wie Sie sehen, werden alle Parameter verwendet werden, vor und das einzige, was die zusätzliche Bedingung am Ende in dieser unterscheidet. Darüber hinaus funktioniert dies in vielen Szenarien. Nur in einem (der dem Rest ähnlich ist) verursacht es den Nullzeiger.

Leider hat der Stack-Trace wirklich nicht in der Sache helfen (try/catch-Block entfernt):

2016-05-06 13:51:14,352 [adnb0007] [main] ERROR o.s.batch.core.step.AbstractStep - Encountered an error executing step prepareDeviceDimensionWrapper in job Load_Devices_Cube 
java.lang.NullPointerException: null 
    at com.aspera.dev.sim.loader.util.partitioning.approximations.ApproximationBuilder.buildQuadraticApproximation(ApproximationBuilder.java:36) 
    at com.aspera.dev.sim.loader.util.ColumnRangePartitioner.partition(ColumnRangePartitioner.java:85) 
    at org.springframework.batch.core.partition.support.SimpleStepExecutionSplitter.getContexts(SimpleStepExecutionSplitter.java:214) 
    at org.springframework.batch.core.partition.support.SimpleStepExecutionSplitter.split(SimpleStepExecutionSplitter.java:177) 
    at org.springframework.batch.core.partition.support.AbstractPartitionHandler.handle(AbstractPartitionHandler.java:59) 
    at org.springframework.batch.core.partition.support.PartitionStep.doExecute(PartitionStep.java:106) 
    at org.springframework.batch.core.step.AbstractStep.execute(AbstractStep.java:200) 
    at org.springframework.batch.core.job.SimpleStepHandler.handleStep(SimpleStepHandler.java:148) 
    at org.springframework.batch.core.job.flow.JobFlowExecutor.executeStep(JobFlowExecutor.java:64) 
    at org.springframework.batch.core.job.flow.support.state.StepState.handle(StepState.java:67) 
    at org.springframework.batch.core.job.flow.support.SimpleFlow.resume(SimpleFlow.java:169) 
    at org.springframework.batch.core.job.flow.support.SimpleFlow.start(SimpleFlow.java:144) 
    at org.springframework.batch.core.job.flow.FlowJob.doExecute(FlowJob.java:134) 
    at org.springframework.batch.core.job.AbstractJob.execute(AbstractJob.java:306) 
    at org.springframework.batch.core.launch.support.SimpleJobLauncher$1.run(SimpleJobLauncher.java:135) 
    at org.springframework.core.task.SyncTaskExecutor.execute(SyncTaskExecutor.java:50) 
    at org.springframework.batch.core.launch.support.SimpleJobLauncher.run(SimpleJobLauncher.java:128) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
    at java.lang.reflect.Method.invoke(Method.java:497) 
    at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:302) 
    at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190) 
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157) 
    at org.springframework.batch.core.configuration.annotation.SimpleBatchConfiguration$PassthruAdvice.invoke(SimpleBatchConfiguration.java:127) 
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) 
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:208) 
    at com.sun.proxy.$Proxy74.run(Unknown Source) 
    at org.springframework.batch.test.JobLauncherTestUtils.launchJob(JobLauncherTestUtils.java:152) 
    at com.aspera.dev.sim.loader.AbstractIntegrationTest.launchJobTest(AbstractIntegrationTest.java:111) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
    at java.lang.reflect.Method.invoke(Method.java:497) 
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50) 
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) 
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47) 
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) 
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26) 
    at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75) 
    at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86) 
    at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84) 
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325) 
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:254) 
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:89) 
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) 
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) 
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) 
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) 
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) 
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61) 
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70) 
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363) 
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:193) 
    at org.apache.maven.surefire.junit4.JUnit4Provider.execute(JUnit4Provider.java:283) 
    at org.apache.maven.surefire.junit4.JUnit4Provider.executeWithRerun(JUnit4Provider.java:173) 
    at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:153) 
    at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:128) 
    at org.apache.maven.surefire.booter.ForkedBooter.invokeProviderInSameClassLoader(ForkedBooter.java:203) 
    at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:155) 
    at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:103) 

I Frühjahr Boot-Version 1.3.3.Release verwenden, Federdaten Gosling-SR1, Frühling Daten Commons 1.11.2 und Spring Batch über Spring-Boot-Starter-Batch.

+2

Überprüfen Sie, dass 'jdbcTemplate' nicht Null . – Berger

+1

Ich denke, es ist ein großer Fehler, eine SQL-Abfrage zu verketten, anstatt PreparedStatement zu verwenden. Diese Art von falschem Denken führt wahrscheinlich zu allen möglichen anderen Problemen. – duffymo

+0

@Berger: Es kann nicht null sein, weil die beiden obigen Zeilen (die auch die gleiche jdbcTemplate verwenden) gut funktionieren. Ich debugge es auch (weil etwas komisches zwischen den Zeilen passieren kann) und jdbcTemplate ist zu diesem Zeitpunkt nicht null. –

Antwort

1

In einigen Szenarien gibt die Abfrage null zurück, weil der Abfragefilter nicht mit den Datensätzen in der Datenbank übereinstimmt. Dies wird eine Nullreferenz zurückgeben, die dann einem Grundwert id_half zugewiesen wird.

Java versucht, eine Null aufzuheben, die eine NullPointerException gibt.

behandeln entweder das Fehlen von Datensätzen in Ihrer Suche entsprechen (möglicherweise DB abhängig sein) wie so

id_half = jdbcTemplate.queryForObject("SELECT COALESCE(MAX(" + column + ") , 0) from " + table + " WHERE " + column + " IS NOT NULL " + " and " + column + " < " + Math.ceil((id_max - id_min)/2.0), Integer.class); 

Oder die Null in Ihrem Java-Code verarbeiten

public static DistributionApproximation buildQuadraticApproximation(JdbcOperations jdbcTemplate, String table, String column) { 
    int id_min = jdbcTemplate.queryForObject("SELECT MIN(" + column + ") from " + table + " WHERE " + column + " IS NOT NULL", Integer.class); 
    int id_max = jdbcTemplate.queryForObject("SELECT MAX(" + column + ") from " + table + " WHERE " + column + " IS NOT NULL", Integer.class); 
    Integer id_half = 0; 

    try { 
     id_half = jdbcTemplate.queryForObject("SELECT MAX(" + column + ") from " + table + " WHERE " + column + " IS NOT NULL " + " and " + column + " < " + Math.ceil((id_max - id_min)/2.0), Integer.class); 
     if(id_half == null){ 
      id_half = (id_max - id_min)/2; 
     } 
    } 
+0

Das war es! Vielen Dank. Ich habe auch einen anderen Fehler gefunden. Wenn ich die "mittlere ID" bekommen möchte, ist der Ausdruck Math.ceil ((id_max - id_min)/2.0) allein falsch (das ist nur der Abstand zwischen min und max). Um die Mitte zu erhalten, muss ich das zusätzlich zu min: min + Math.ceil ((id_max - id_min)/2.0) hinzufügen. Dadurch wird auch sichergestellt, dass SQL einen Datensatz findet, aber ich werde auch Ihren Vorschlag hinzufügen. –