When creating a FeatureLayer from a FeatureTable I get an ArcGISRuntimeException: Invalid argument in JNI code

1629
10
02-21-2018 09:28 PM
ChristopherMugdan
New Contributor III

ArcGIS Java SDK 100.2

I am new to the Java SDK and I am trying a simple test case to create an image from an ArcGISMap with a few points in it. When I try to run it I get the following when I try to create  FeatureLayer from a FeatureCollectionTable:

Exception in thread "main" com.esri.arcgisruntime.ArcGISRuntimeException: Invalid argument
    at com.esri.arcgisruntime.internal.jni.CoreFeatureLayer.nativeCreateWithFeatureTable(Native Method)
    at com.esri.arcgisruntime.internal.jni.CoreFeatureLayer.<init>(SourceFile:67)
    at com.esri.arcgisruntime.layers.FeatureLayer.a(SourceFile:209)
    at com.esri.arcgisruntime.layers.FeatureLayer.<init>(SourceFile:194)

I could not see how to create a FeatureTable from some Features, hence my use of a FeatureCollectionTable. Maybe that is incorrect?

I have set the environment variable ARCGISRUNTIMESDKJAVA_100_2_0 to the correct path to find the JNI code which I presume is in jniLibs under that path?

I have attached the (very simple) test code. I presume I have missed something but what?

Cheers,
Chris Mugdan

0 Kudos
10 Replies
TylerSchiewe
New Contributor II

Hi Chris,

Welcome to the Java SDK!

I don't think the problem is with the jniLibs. I would expect your app to throw an exception much earlier with a message like "Failed to location the SDK..." if that were the case. I believe the problem is where you directly create a feature layer from the feature table you created.

I have attached the source code for a JavaFX application which does what you want. Most of the logic comes from these samples: arcgis-runtime-samples-java/src/main/java/com/esri/samples/featurelayers/feature_collection_layer at... , arcgis-runtime-samples-java/src/main/java/com/esri/samples/mapview/take_screen_shot at master · Esri... . Let me know if it doesn't work for you.

Cheers,

Tyler

0 Kudos
ChristopherMugdan
New Contributor III

Hi Tyler,

Thanks for the response, it is much appreciated. I modified the code as per the first example and that all works fine now. I am starting to get a feel for the operation of the SDK bit by bit. However, now that I have the map and mapView, when I try to render the image as per the second example, it hangs when the "addDoneListener" line executes and the actions in that listener lambda do not get executed. The test program does not exit. I have appended the modified code. It would be really nice to have synchronous versions of the current asynchronous operations for our purposes (see below.)

I should explain that our application Map Intelligence is not the type of application that the SDK usually supports. It is a web application (installed in Tomcat by default) that renders maps in its own UI. We currently connect to the ArcGIS Server using the REST interface to render maps (with map services) and I was hoping to do something similar with the ArcGIS Java SDK so that we can connect to ArcGIS Online. We do not use the JavaFX library at all and this is the first time I have needed to get involved in it.

I am wondering if the hanging request is because the JavaFX library is not properly set up? Do you have an explanation?

A question on the use of the get() method in the Listenable Future: in the Java Future class the get() method waits on the conclusion of the asynchronous action. I see that the ListenableFuture overrides this method. When is it acceptable to use the get() method in the ArcGIS Java SDK?

Cheers,
Chris

 The modified code:

com.sun.javafx.application.PlatformImpl.startup(()->{});

MapView mapView = new MapView();
SpatialReference sr = SpatialReference.create(4326);
ArcGISMap map = new ArcGISMap(sr);
ArrayList<Field> fields = new ArrayList<>();
fields.add(Field.createInteger("ID", "ID"));
fields.add(Field.createString("NAME", "NAME", 256));
FeatureCollectionTable ft = new FeatureCollectionTable(fields, GeometryType.POINT, sr);
ArrayList<Feature> features = new ArrayList<>();
HashMap<String,Object> attrs1 = new HashMap<>();
attrs1.put("ID", 1);
attrs1.put("NAME", "point 1");
Geometry geom1 = new Point(151.096, -33.709, sr);
Feature f1 = ft.createFeature(attrs1, geom1);
features.add(f1);
HashMap<String,Object> attrs2 = new HashMap<>();
attrs2.put("ID", 2);
attrs2.put("NAME", "point 2");
Geometry geom2 = new Point(151.091, -33.706, sr);
Feature f2 = ft.createFeature(attrs2, geom2);
features.add(f2);
HashMap<String,Object> attrs3 = new HashMap<>();
attrs3.put("ID", 3);
attrs3.put("NAME", "point 3");
Geometry geom3 = new Point(151.103, -33.704, sr);
Feature f3 = ft.createFeature(attrs3, geom3);
features.add(f3);
ListenableFuture<Void> loaded = ft.addFeaturesAsync(features);
try
{
   loaded.get();
}
catch (Throwable t)
{
   System.out.println(t.getMessage());
}

FeatureCollection fc = new FeatureCollection();
Renderer rdr = new SimpleRenderer();
ft.setRenderer(rdr);
fc.getTables().add(ft);
FeatureCollectionLayer fl = new FeatureCollectionLayer(fc);
map.getOperationalLayers().add(fl);
mapView.setMap(map);
Envelope e = new Envelope(151.090, -33.713, 151.107, -33.702, sr);
Viewpoint vp = new Viewpoint(e);
mapView.setViewpoint(vp);
ListenableFuture<Image> imageResult = mapView.exportImageAsync();
imageResult.addDoneListener(() ->
{
    try {
      // get image
      Image image = imageResult.get();
      // choose a location to save the file
      File file = new File("C:/tmp/img.png");
      if (file != null) {
        // write the image to the save location
        ImageIO.write(SwingFXUtils.fromFXImage(image, null), "png", file);
      }
    }
    catch (Exception ex)
    {
      ex.printStackTrace();
    }
    finally
    {
        mapView.dispose();
    }
});
0 Kudos
TylerSchiewe
New Contributor II

Glad to hear that code is working for you.

As for the use of get(): It should work exactly the same as Java's Futures. We only extend it to add the listeners. I'm almost certain it's not working because some rendering isn't working in a web server environment and so the async operation never completes.

The Java SDK is intended only for desktop JavaFX client applications. I also believe this is the only environment our licensing permits. Since our view components (MapView) are all based on top of JavaFX components, they will likely only work where JavaFX components work (on the desktop). If you only want to be able to render maps in your web app's front-end, I would suggest using the Javascript API ArcGIS API for JavaScript | ArcGIS for Developers . If on the back-end, that's probably a bit trickier, and I'm not aware of a solution (I'm just a product engineer). Maybe Eric Bader can help with that?

Sorry I couldn't help you more. If you have any more questions about using the SDK with JavaFX in a desktop environment, I'm happy to help. I wrote many of the samples that we have on GitHub.

Cheers,

Tyler

0 Kudos
ChristopherMugdan
New Contributor III

Hi Tyler,

The code hangs even when in an entirely isolated environment and not in our Web application. Could it be that I have not extended javafx.application.Application nor have I created a Stage or Scene?

Would you be able to try the code yourself and see what you get?

Cheers,
Chris

0 Kudos
TylerSchiewe
New Contributor II

Yes. I'm pretty sure you would need to create a standard app (extend Application with a stage and scene) for any of our code to work. The MapView probably wouldn't know how to render anything without being in a scene/stage. But again, this is outside of our normal use so I don't have much experience with this kind of workflow.

Again, the Java SDK wasn't intended for this use case. You might look into the ArcGIS API for Python. I don't have any experience with it, but I think it is more suited toward this kind of back-end scripting workflow. I believe it can also work with maps on ArcGIS Online and export the map to an image: arcgis.mapping module — arcgis 1.3.0 documentation . If you needed to call it from your Java web app, you might look into Jython for that.

0 Kudos
ChristopherMugdan
New Contributor III

Hi Tyler,

It would seem that the current SDK is not ideal for our purposes. I shall investigate the Python engine. Thanks for your assistance.

0 Kudos
EricBader
Occasional Contributor III

Hi Chris,

We would definitely be interested in hearing more about your desired back-end server use cases. 

As Tyler indicated, the ArcGIS Runtime SDK does not have a license model at this time for use behind a web server. (We do understand, however, that this would be an appealing use case and a preferred choice of architecture for Java developers.)

Regarding what you can do today with a Java API on the back-end, ArcGIS Server services can be extended with Server Object Extensions and Server Object Interceptors using the ArcObjects SDK for Java. You might find the ArcObjects SDK GeoNet community helpful as well.

Cheers,

Eric

0 Kudos
ChristopherMugdan
New Contributor III

Hi Eric,

Our application Map Intelligence is a Java Web application that is usually installed in a Tomcat Web container. It has its own user interface that renders maps inside Business Intelligence tools. We have adapters for a number of GIS back ends including one for ArcGIS Server. Currently the adapter connects to the REST interface of ArcGIS Server to render maps from map services. We want to do the same with ArcGIS Online web maps and that is why I have been investigating the ArcGIS Java SDK as I thought it would be suitable to fetch the layer data from ArcGIS Online and render the maps locally based on local content and the ArcGIS Online layers.

Have a look at our website: www.integeo.com to see who we are and there is a demo map viewer using ArcGIS Server at http://arcdemo.development.integeo.com/mapIntelligence

Any suggestions based on the above model would be gratefully received.

Cheers,
Chris

EricBader
Occasional Contributor III

Thank you, Chris. This is very insightful! I'll record your response and keep it under consideration. I understand a lot more now. 

Eric

0 Kudos