Author: jcouteau Date: 2010-05-14 11:23:03 +0200 (Fri, 14 May 2010) New Revision: 215 Url: http://nuiton.org/repositories/revision/nuiton-j2r/215 Log: Fix NPE when getting list with anonymous elements Modified: trunk/src/main/java/org/nuiton/j2r/jni/RJniEngine.java trunk/src/main/java/org/nuiton/j2r/net/RNetEngine.java trunk/src/main/java/org/nuiton/j2r/types/RList.java trunk/src/test/java/org/nuiton/j2r/JNITest.java trunk/src/test/java/org/nuiton/j2r/ListTest.java trunk/src/test/java/org/nuiton/j2r/NetTest.java Modified: trunk/src/main/java/org/nuiton/j2r/jni/RJniEngine.java =================================================================== --- trunk/src/main/java/org/nuiton/j2r/jni/RJniEngine.java 2010-05-09 12:34:27 UTC (rev 214) +++ trunk/src/main/java/org/nuiton/j2r/jni/RJniEngine.java 2010-05-14 09:23:03 UTC (rev 215) @@ -25,11 +25,6 @@ package org.nuiton.j2r.jni; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.LinkedList; -import java.util.List; - import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.nuiton.j2r.REngine; @@ -41,6 +36,11 @@ import org.rosuda.JRI.REXP; import org.rosuda.JRI.Rengine; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; + /** * RJniEngine.java * @@ -300,21 +300,40 @@ protected RList convertToRList(REXP rexp){ RList temp = new RList(this); List<Object> data = new ArrayList<Object>(); + + //get the names of the list objects + REXP attrNames = rexp.getAttribute(RInstructions.ATTRIBUTE_NAMES); + String[] names = {}; + if (attrNames != null) { + names = attrNames.asStringArray(); + } + org.rosuda.JRI.RList dataList = rexp.asList(); - for (int i = 0; i < dataList.keys().length; i++) { + + //Use this because do not have a size() or length() method, cannot use + // the keys size (elements might not have keys) and RList do not throw + // out of bound exception if going to far. + Boolean flag = true; + int index = 0; + + while (flag) { //for each object of the list, convert it to java. - REXP tempREXP = dataList.at(i); - Object convertedREXP = convertResult(tempREXP); - //add this object to the data list. - data.add(convertedREXP); + REXP tempREXP = dataList.at(index); + + if (tempREXP == null) { + flag = false; + } else { + Object convertedREXP = convertResult(tempREXP); + //add this object to the data list. + data.add(convertedREXP); + index++; + } } //Create a new list with the names and data //gotten from rexp. It has no variable name so throws a //RException. try { - temp = new RList( - rexp.getAttribute(RInstructions.ATTRIBUTE_NAMES).asStringArray(), - data, this, ""); + temp = new RList(names, data, this, ""); } catch (RException re) { //don't propagate the error as it is normal. Log it for debug. if (log.isDebugEnabled()) { Modified: trunk/src/main/java/org/nuiton/j2r/net/RNetEngine.java =================================================================== --- trunk/src/main/java/org/nuiton/j2r/net/RNetEngine.java 2010-05-09 12:34:27 UTC (rev 214) +++ trunk/src/main/java/org/nuiton/j2r/net/RNetEngine.java 2010-05-14 09:23:03 UTC (rev 215) @@ -32,11 +32,6 @@ */ package org.nuiton.j2r.net; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.LinkedList; -import java.util.List; - import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.nuiton.j2r.REngine; @@ -44,12 +39,17 @@ import org.nuiton.j2r.RException; import org.nuiton.j2r.RInstructions; import org.nuiton.j2r.types.RDataFrame; +import org.nuiton.j2r.types.RList; import org.rosuda.REngine.REXP; import org.rosuda.REngine.REXPMismatchException; -import org.nuiton.j2r.types.RList; import org.rosuda.REngine.Rserve.RConnection; import org.rosuda.REngine.Rserve.RserveException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; + /** * This class represents the network engine to access R. By default, it tries to * connect on address 127.0.0.1 and port 6311. Meanwhile, it is possible to @@ -318,7 +318,16 @@ protected RList convertToRList (REXP rexp) throws REXPMismatchException { RList temp = new RList(this); List<Object> data = new ArrayList<Object>(); + + //get the names of the list objects + REXP attrNames = rexp.getAttribute(RInstructions.ATTRIBUTE_NAMES); + String[] names = {}; + if (attrNames!=null){ + names = attrNames.asStrings(); + } + org.rosuda.REngine.RList dataList = rexp.asList(); + for (int i = 0; i < dataList.size(); i++) { //for each vector, create a list and fill it with the //content of the vector. @@ -328,13 +337,11 @@ data.add(convertedREXP); } - //Create a new dataframe with the names, row.names and data + //Create a new list with the names and data //gotten from rexp. It has no variable name so throws a //RException. try { - temp = new RList(rexp.getAttribute( - RInstructions.ATTRIBUTE_NAMES).asStrings(), - data, this, ""); + temp = new RList(names, data, this, ""); } catch (RException re) { //don't propagate the error as it is normal. Log it for debug. if (log.isDebugEnabled()) { Modified: trunk/src/main/java/org/nuiton/j2r/types/RList.java =================================================================== --- trunk/src/main/java/org/nuiton/j2r/types/RList.java 2010-05-09 12:34:27 UTC (rev 214) +++ trunk/src/main/java/org/nuiton/j2r/types/RList.java 2010-05-14 09:23:03 UTC (rev 215) @@ -319,11 +319,13 @@ * x coordinates (between 0 and size-1) * @return the Object located at the [x] coordinate * @throws RException - * if no variable name has been given to the list + * if no variable name has been given to the list and tries to + * retrieve data from R */ public Object get(int x) throws RException { checkX(x); if (engine.isAutoCommit()) { + checkVariable(); Object returnObject = engine.eval(String.format( RInstructions.GET_LIST_ITEM, this.variable, x + 1)); if (returnObject instanceof String) { Modified: trunk/src/test/java/org/nuiton/j2r/JNITest.java =================================================================== --- trunk/src/test/java/org/nuiton/j2r/JNITest.java 2010-05-09 12:34:27 UTC (rev 214) +++ trunk/src/test/java/org/nuiton/j2r/JNITest.java 2010-05-14 09:23:03 UTC (rev 215) @@ -35,17 +35,6 @@ * par : */ package org.nuiton.j2r; -import static org.nuiton.j2r.TestConstants.S_NB_LOOPS; -import static org.nuiton.j2r.TestConstants.S_OP; -import static org.nuiton.j2r.TestConstants.S_T_MAX; -import static org.nuiton.j2r.TestConstants.V_MAX; -import static org.nuiton.j2r.TestConstants.V_NB_LOOPS; -import static org.nuiton.j2r.TestConstants.V_OP_A; -import static org.nuiton.j2r.TestConstants.V_OP_AB; -import static org.nuiton.j2r.TestConstants.V_OP_B; -import static org.nuiton.j2r.TestConstants.V_OP_R; -import java.io.File; - import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.junit.After; @@ -55,6 +44,10 @@ import org.nuiton.j2r.types.RDataFrame; import org.nuiton.j2r.types.RList; +import java.io.File; + +import static org.nuiton.j2r.TestConstants.*; + public class JNITest { private static Log log = LogFactory.getLog(JNITest.class); @@ -405,4 +398,20 @@ Assert.fail("Error should not have been thrown : " + npe); } } + + @Test + public void testListWithNullNames() throws Exception { + RList b= new RList(engine); + try { + b = (RList)engine.eval("b<-list(\"a\",\"b\")"); + b.setVariable("b"); + } catch (NullPointerException npe) { + npe.printStackTrace(); + Assert.fail("Error should not have been thrown : " + npe); + } + + Assert.assertEquals("a",b.get(0)); + Assert.assertEquals("b", b.get(1)); + + } } // JNITest Modified: trunk/src/test/java/org/nuiton/j2r/ListTest.java =================================================================== --- trunk/src/test/java/org/nuiton/j2r/ListTest.java 2010-05-09 12:34:27 UTC (rev 214) +++ trunk/src/test/java/org/nuiton/j2r/ListTest.java 2010-05-14 09:23:03 UTC (rev 215) @@ -25,13 +25,6 @@ package org.nuiton.j2r; -import static org.junit.Assert.assertEquals; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.junit.After; @@ -40,6 +33,13 @@ import org.junit.Test; import org.nuiton.j2r.types.RList; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.junit.Assert.assertEquals; + public class ListTest { private static Log log = LogFactory.getLog(DataframeTest.class); @@ -922,4 +922,8 @@ engine.setAutoCommit(true); } + + + + } Modified: trunk/src/test/java/org/nuiton/j2r/NetTest.java =================================================================== --- trunk/src/test/java/org/nuiton/j2r/NetTest.java 2010-05-09 12:34:27 UTC (rev 214) +++ trunk/src/test/java/org/nuiton/j2r/NetTest.java 2010-05-14 09:23:03 UTC (rev 215) @@ -359,4 +359,19 @@ Assert.fail("Error should not have been thrown : " + npe); } } + + @Test + public void testListWithNullNames() throws Exception { + RList b = new RList(engine); + try { + b = (RList) engine.eval("b<-list(\"b\",\"a\")"); + b.setVariable("b"); + } catch (NullPointerException npe) { + Assert.fail("Error should not have been thrown : " + npe); + } + + Assert.assertEquals("b", b.get(0)); + Assert.assertEquals("a", b.get(1)); + + } } // NetTest