<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:taxo="http://purl.org/rss/1.0/modules/taxonomy/" version="2.0">
  <channel>
    <title>topic Re: calling Java methods from SAS data step, array argument and return value in SAS Programming</title>
    <link>https://communities.sas.com/t5/SAS-Programming/calling-Java-methods-from-SAS-data-step-array-argument-and/m-p/633864#M188074</link>
    <description>&lt;P&gt;Unfortunately DATA step component object JavaObj does not have a built-in method for returning Java arrays to DATA step arrays.&lt;/P&gt;
&lt;P&gt;Should it ? Maybe, but I speculate the demand for such is so low that it does not warrant the development time and support costs.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;You can pass arrays of either String or Double into Java methods, but any changes made to those arrays in the method do not get reflected back to the DATA step array.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;An adapter class is needed for the cases when you need an array in Java to be accessed in DATA step.&amp;nbsp;&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Tip: You can easily "fiddle around with" (develop) adapter classes in a SAS session by compiling them in a Proc GROOVY step and then accessing them in DATA step via JavaObj.&lt;/LI&gt;
&lt;LI&gt;Tip: GROOVY classes need a &lt;FONT face="courier new,courier"&gt;main()&lt;/FONT&gt; method, otherwise the Proc will log an ERROR and exception&amp;nbsp;&lt;FONT face="courier new,courier"&gt;org.codehaus.groovy.runtime.metaclass.MissingMethodExceptionNoStack&lt;BR /&gt;&lt;/FONT&gt;&lt;/LI&gt;
&lt;/UL&gt;
&lt;P&gt;The JavaObj provides a bridge to hosted class methods via its JavaObj methods whose names are:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;&lt;FONT face="courier new,courier"&gt;call&amp;lt;type&amp;gt;Method(&amp;lt;method-name&amp;gt;, &amp;lt;arg-1&amp;gt; ... &amp;lt;arg-n&amp;gt;, &amp;lt;method-return&amp;gt;)&lt;/FONT&gt;&lt;/LI&gt;
&lt;/UL&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;FONT size="5"&gt;&lt;STRONG&gt;Fiddling around #1&lt;/STRONG&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;This code shows an array passed to a Java method and its elements get changed therein.&amp;nbsp; The changes do not get reflected back to the array in the calling DATA step.&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;proc groovy;
  clear;   * clean slate;
  submit;
    class Example {
      public String hello() {
        return "Hello from a groovy class";
      }
      public void log (String string) {
        System.out.println("NOTE: Stdout of JVM says: " + string);
      }
      public void fill(String[] target) {
        for (int i=1; i&amp;lt;=target.length; i++)
        {
          target[i-1] = i.toString();
        }
        System.out.println("NOTE: Stdout of JVM says: " +target);
      }
      void main() { 
        // a main is required to prevent groovy errors while 
        // allowing compilation and loading of the class into the JVM
      }
    }
  endsubmit;
quit;


data _null_;
  array number_strings [10] $3 ('abc', 'def', 'ghi', 'jkl', 'mno', 'pqr', 'stu');
  length s $200;

  declare JavaObj j ('Example');

  j.callStringMethod ('hello', s);
  put s=;

  j.callVoidMethod ('log', 'This is a message');

  put 'NOTE: data step array before "fill": ' number_strings(*);

  j.callVoidMethod ('fill', number_strings);

  put 'NOTE: data step array after  "fill": ' number_strings(*);
run;&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;Log&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;s=Hello from a groovy class
NOTE: data step array before "fill": abc def ghi jkl mno pqr stu
NOTE: data step array after  "fill": abc def ghi jkl mno pqr stu
NOTE: Stdout of JVM says: This is a message
NOTE: Stdout of JVM says: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;&lt;FONT size="5"&gt;&lt;STRONG&gt;Fiddling around #2&lt;/STRONG&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;Add an adapter class named &lt;FONT face="courier new,courier"&gt;StringArray&lt;/FONT&gt; to the mix.&amp;nbsp; The Java array data lives in the adapter instance and the array elements are accessible through the adapter class methods &lt;FONT face="courier new,courier"&gt;get&lt;/FONT&gt; and &lt;FONT face="courier new,courier"&gt;set&lt;/FONT&gt;.&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;proc groovy;
  clear;   * clean slate;
  submit;
class StringArray
{
    private String[] values;

    int getLength () { return (values == null) ? 0 : values.length }

    void setLength (double dlength)
    {
        int length = (dlength &amp;gt;= 0) ? (int) dlength : 0;
        values = new String[length];
    }

    String get (double dindex) // accesor method callable via JavaObj
    {
      int index = (int) dindex;

      String result = 
        values == null
        ? "" 
        : index &amp;gt;= 0 &amp;amp;&amp;amp; index &amp;lt; values.length &amp;amp;&amp;amp; values[index] != null
          ? values[index] 
          : "";

      return result;
    }

    void set (double dindex, String value) // accesor method callable via JavaObj
    {
      int index = (int) dindex;

      if (values == null)
        return ;
      else
      if (index &amp;gt;= 0 &amp;amp;&amp;amp; index &amp;lt; values.length)
        values[index] = value;
    }

    String toString() {
      return values.toString();
    }

    void main() { }
}

class Example {
  public void fill(StringArray target) {
    for (int i=1; i&amp;lt;=target.getLength(); i++)
    {
      target.set(i-1, ((char)(i+64)).toString());
    }
    System.out.println("NOTE: Stdout of JVM. fill() says: " +target.toString());
  }
  void main() { 
    // a main is required to prevent groovy errors while 
    // allowing compilation and loading of the class into the JVM
  }
}
  endsubmit;
quit;

data _null_;
  declare javaobj sa ('StringArray');
  declare javaobj ex ('Example');

  sa.callVoidMethod('setLength', 8);
  ex.callVoidMethod('fill', sa);

  length sa_string $200;
  sa.callStringMethod('toString', sa_string);
  put 'NOTE: ' sa_string=;

  length _5th_element_value $20;
  sa.callStringMethod('get', 4, _5th_element_value);
  put 'NOTE: ' _5th_element_value=;

  sa.callVoidMethod('set', 4, "It works!");
  sa.callStringMethod('get', 4, _5th_element_value);
  put 'NOTE: ' _5th_element_value=;
run;&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;Log&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;NOTE: sa_string=[A, B, C, D, E, F, G, H]
NOTE: _5th_element_value=E
NOTE: _5th_element_value=It works!
NOTE: Stdout of JVM. fill() says: [A, B, C, D, E, F, G, H]
&lt;/CODE&gt;&lt;/PRE&gt;</description>
    <pubDate>Sat, 21 Mar 2020 19:41:42 GMT</pubDate>
    <dc:creator>RichardDeVen</dc:creator>
    <dc:date>2020-03-21T19:41:42Z</dc:date>
    <item>
      <title>calling Java methods from SAS data step, array argument and return value</title>
      <link>https://communities.sas.com/t5/SAS-Programming/calling-Java-methods-from-SAS-data-step-array-argument-and/m-p/614709#M179769</link>
      <description>&lt;P&gt;Hello&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;from the data step, I can call methods on Java classes with array arguments. A metod with this signature is fine:&amp;nbsp;public void str(String args[]).&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;However, returning arrays seems to be impossible. I cannot get a call to a method with this signature to work: public String [] str(String args[]).&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;Should this be possible?&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;If so, how?&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;Thank you&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;Niels Jespersen&lt;/P&gt;</description>
      <pubDate>Thu, 02 Jan 2020 07:32:05 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/calling-Java-methods-from-SAS-data-step-array-argument-and/m-p/614709#M179769</guid>
      <dc:creator>njespersen</dc:creator>
      <dc:date>2020-01-02T07:32:05Z</dc:date>
    </item>
    <item>
      <title>Re: calling Java methods from SAS data step, array argument and return value</title>
      <link>https://communities.sas.com/t5/SAS-Programming/calling-Java-methods-from-SAS-data-step-array-argument-and/m-p/633864#M188074</link>
      <description>&lt;P&gt;Unfortunately DATA step component object JavaObj does not have a built-in method for returning Java arrays to DATA step arrays.&lt;/P&gt;
&lt;P&gt;Should it ? Maybe, but I speculate the demand for such is so low that it does not warrant the development time and support costs.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;You can pass arrays of either String or Double into Java methods, but any changes made to those arrays in the method do not get reflected back to the DATA step array.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;An adapter class is needed for the cases when you need an array in Java to be accessed in DATA step.&amp;nbsp;&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Tip: You can easily "fiddle around with" (develop) adapter classes in a SAS session by compiling them in a Proc GROOVY step and then accessing them in DATA step via JavaObj.&lt;/LI&gt;
&lt;LI&gt;Tip: GROOVY classes need a &lt;FONT face="courier new,courier"&gt;main()&lt;/FONT&gt; method, otherwise the Proc will log an ERROR and exception&amp;nbsp;&lt;FONT face="courier new,courier"&gt;org.codehaus.groovy.runtime.metaclass.MissingMethodExceptionNoStack&lt;BR /&gt;&lt;/FONT&gt;&lt;/LI&gt;
&lt;/UL&gt;
&lt;P&gt;The JavaObj provides a bridge to hosted class methods via its JavaObj methods whose names are:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;&lt;FONT face="courier new,courier"&gt;call&amp;lt;type&amp;gt;Method(&amp;lt;method-name&amp;gt;, &amp;lt;arg-1&amp;gt; ... &amp;lt;arg-n&amp;gt;, &amp;lt;method-return&amp;gt;)&lt;/FONT&gt;&lt;/LI&gt;
&lt;/UL&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;FONT size="5"&gt;&lt;STRONG&gt;Fiddling around #1&lt;/STRONG&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;This code shows an array passed to a Java method and its elements get changed therein.&amp;nbsp; The changes do not get reflected back to the array in the calling DATA step.&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;proc groovy;
  clear;   * clean slate;
  submit;
    class Example {
      public String hello() {
        return "Hello from a groovy class";
      }
      public void log (String string) {
        System.out.println("NOTE: Stdout of JVM says: " + string);
      }
      public void fill(String[] target) {
        for (int i=1; i&amp;lt;=target.length; i++)
        {
          target[i-1] = i.toString();
        }
        System.out.println("NOTE: Stdout of JVM says: " +target);
      }
      void main() { 
        // a main is required to prevent groovy errors while 
        // allowing compilation and loading of the class into the JVM
      }
    }
  endsubmit;
quit;


data _null_;
  array number_strings [10] $3 ('abc', 'def', 'ghi', 'jkl', 'mno', 'pqr', 'stu');
  length s $200;

  declare JavaObj j ('Example');

  j.callStringMethod ('hello', s);
  put s=;

  j.callVoidMethod ('log', 'This is a message');

  put 'NOTE: data step array before "fill": ' number_strings(*);

  j.callVoidMethod ('fill', number_strings);

  put 'NOTE: data step array after  "fill": ' number_strings(*);
run;&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;Log&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;s=Hello from a groovy class
NOTE: data step array before "fill": abc def ghi jkl mno pqr stu
NOTE: data step array after  "fill": abc def ghi jkl mno pqr stu
NOTE: Stdout of JVM says: This is a message
NOTE: Stdout of JVM says: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;&lt;FONT size="5"&gt;&lt;STRONG&gt;Fiddling around #2&lt;/STRONG&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;Add an adapter class named &lt;FONT face="courier new,courier"&gt;StringArray&lt;/FONT&gt; to the mix.&amp;nbsp; The Java array data lives in the adapter instance and the array elements are accessible through the adapter class methods &lt;FONT face="courier new,courier"&gt;get&lt;/FONT&gt; and &lt;FONT face="courier new,courier"&gt;set&lt;/FONT&gt;.&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;proc groovy;
  clear;   * clean slate;
  submit;
class StringArray
{
    private String[] values;

    int getLength () { return (values == null) ? 0 : values.length }

    void setLength (double dlength)
    {
        int length = (dlength &amp;gt;= 0) ? (int) dlength : 0;
        values = new String[length];
    }

    String get (double dindex) // accesor method callable via JavaObj
    {
      int index = (int) dindex;

      String result = 
        values == null
        ? "" 
        : index &amp;gt;= 0 &amp;amp;&amp;amp; index &amp;lt; values.length &amp;amp;&amp;amp; values[index] != null
          ? values[index] 
          : "";

      return result;
    }

    void set (double dindex, String value) // accesor method callable via JavaObj
    {
      int index = (int) dindex;

      if (values == null)
        return ;
      else
      if (index &amp;gt;= 0 &amp;amp;&amp;amp; index &amp;lt; values.length)
        values[index] = value;
    }

    String toString() {
      return values.toString();
    }

    void main() { }
}

class Example {
  public void fill(StringArray target) {
    for (int i=1; i&amp;lt;=target.getLength(); i++)
    {
      target.set(i-1, ((char)(i+64)).toString());
    }
    System.out.println("NOTE: Stdout of JVM. fill() says: " +target.toString());
  }
  void main() { 
    // a main is required to prevent groovy errors while 
    // allowing compilation and loading of the class into the JVM
  }
}
  endsubmit;
quit;

data _null_;
  declare javaobj sa ('StringArray');
  declare javaobj ex ('Example');

  sa.callVoidMethod('setLength', 8);
  ex.callVoidMethod('fill', sa);

  length sa_string $200;
  sa.callStringMethod('toString', sa_string);
  put 'NOTE: ' sa_string=;

  length _5th_element_value $20;
  sa.callStringMethod('get', 4, _5th_element_value);
  put 'NOTE: ' _5th_element_value=;

  sa.callVoidMethod('set', 4, "It works!");
  sa.callStringMethod('get', 4, _5th_element_value);
  put 'NOTE: ' _5th_element_value=;
run;&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;Log&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;NOTE: sa_string=[A, B, C, D, E, F, G, H]
NOTE: _5th_element_value=E
NOTE: _5th_element_value=It works!
NOTE: Stdout of JVM. fill() says: [A, B, C, D, E, F, G, H]
&lt;/CODE&gt;&lt;/PRE&gt;</description>
      <pubDate>Sat, 21 Mar 2020 19:41:42 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/calling-Java-methods-from-SAS-data-step-array-argument-and/m-p/633864#M188074</guid>
      <dc:creator>RichardDeVen</dc:creator>
      <dc:date>2020-03-21T19:41:42Z</dc:date>
    </item>
    <item>
      <title>Re: calling Java methods from SAS data step, array argument and return value</title>
      <link>https://communities.sas.com/t5/SAS-Programming/calling-Java-methods-from-SAS-data-step-array-argument-and/m-p/633971#M188134</link>
      <description>Thanks a lot. Impressive work. My original problem found another solution not involving SAS or Java. Hopefully your work can be used by others with similar problems.&lt;BR /&gt;&lt;BR /&gt;Regards Niels Jespersen</description>
      <pubDate>Sun, 22 Mar 2020 17:49:18 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/calling-Java-methods-from-SAS-data-step-array-argument-and/m-p/633971#M188134</guid>
      <dc:creator>njespersen</dc:creator>
      <dc:date>2020-03-22T17:49:18Z</dc:date>
    </item>
    <item>
      <title>Re: calling Java methods from SAS data step, array argument and return value</title>
      <link>https://communities.sas.com/t5/SAS-Programming/calling-Java-methods-from-SAS-data-step-array-argument-and/m-p/634018#M188146</link>
      <description>&lt;P&gt;Thanks Niels.&lt;/P&gt;
&lt;P&gt;I developed the concepts quite a while ago for the SUGI 30 conference paper &lt;A title="Landing page for Richard's SUGI 30 papers." href="https://www.devenezia.com/papers/sugi-30/index.html" target="_blank" rel="noopener"&gt;"Java in SAS®:&lt;/A&gt;&lt;BR /&gt;&lt;A title="Landing page for Richard's SUGI 30 papers." href="https://www.devenezia.com/papers/sugi-30/index.html" target="_blank" rel="noopener"&gt;JavaObj, a DATA Step Component Object"&lt;/A&gt;&amp;nbsp;and demonstration code &lt;A href="https://www.devenezia.com/downloads/sas/samples/#jdsgi" target="_self"&gt;jDSGI&lt;/A&gt;&lt;/P&gt;</description>
      <pubDate>Mon, 23 Mar 2020 00:40:52 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/calling-Java-methods-from-SAS-data-step-array-argument-and/m-p/634018#M188146</guid>
      <dc:creator>RichardDeVen</dc:creator>
      <dc:date>2020-03-23T00:40:52Z</dc:date>
    </item>
  </channel>
</rss>

