So I undertook to port our Server Object Extensions from ArcObjects for .NET to ArcObjects for Java. It wasn't a huge undertaking, but the extremely long cycle of compile/deploy SOE/deploy MapServer/test/delete MapServer/delete SOE/repeat made it much more time-consuming than it should have been. I'm posting some of the pitfalls I ran into here, in the hopes that it saves someone else some time.
1. Don't change the method signatures
This was a tough one to track down. The methods defined by the IServerObjectExtension, IObjectConstruct, and IRESTRequestHandler interfaces all have a throws clause of IOException, AutomationException. You might say to yourself, "that's redundant; AutomationException is a subclass of IOException. I'll just abbreviate that by removing AuomationException." Don't do that. The Java compiler won't complain, but ArcGIS Server won't be able to call your methods because the signatures don't exactly match what it's looking for. Your extension will fail to load, and you won't have any debug information because none of your methods will ever get called. Seriously, just don't do it.
2. Don't bother with ILogSupport
I'm not sure why, but I was never able to convince the server to call my initLogging(ILog) method. That's how you set up the logger in C#, and the interface exists in Java, so I assumed that was the way it's done. I was wrong. The correct way to set up the logger in Java is (in your init method):
m_logger = ServerUtilities.getServerLogger();It's really that easy. In fact the ServerUtilities class does a few neat things that don't have any equivalent in ArcObjects for C#.
3. ServerUtilities: win some, lose some
Win:
ServerUtilities.getSRFromJSON(JSONObject) - no more custom JSON parsing for SpatialReference objects!Lose:
ServerUtilities.getJSONFromGeometry(IGeometry) - works for Point, Polyline, but throws an error when called on a Polygon, saying that Polygon is "not simple". Fortunately, you can always use getJSONFromPolygon, but why can't getJSONFromGeometry call it for me?
4. IMapServerDataAccess: same name, different semantics
ArcObjects for .NET has an IMapServerDataAccess interface, and so does ArcObjects for Java, and both define a getDataSource(String,int) method. You might assume that they behave the same, but you would be wrong. The .NET version, GetDataSource, returns an IFeatureService, IRaster, or ITable, depending on the layer type. For example:
IFeatureClass fc = dataAccess.GetDataSource(mapServer.DefaultMapName, 0) as IFeatureClass; IRaster ras = dataAccess.GetDataSource(mapServer.DefaultMapName, 1) as IRaster;The Java version, getDataSource, returns a com.esri.arcgis.interop.RemoteObjRef, which you have to pass to a constructor to get an IFeatureClass or IRaster.
IFeatureClass fc = new FeatureClass(dataAccess.getDataSource(mapServer.getDefaultMapName(), 0)); IRaster ras = new Raster(dataAccess.getDataSource(mapServer.getDefaultMapName(), 1));You may notice that the Raster constructor is deprecated. As far as I know, there isn't any way to get an IRaster from the IMapServerDataAccess without using the deprecated constructor, but I've posted an inquiry to the ArcGIS Forum, and I'll update this post if it turns out that a way does exist.
5. Sometimes you cast, sometimes you don't
This brings up another subtle difference between ArcObjects for .NET and Java. In ArcObjects for .NET, you always convert objects from one type to another by casting. In ArcObjects for Java, sometimes you use casing, and sometimes you create a proxy object. For example, C#:
IRasterBand band = (ras as IRasterBandCollection).Item(0); IRawPixels pixels = band as IRawPixels; IRasterProps properties = band as IRasterProps;vs. Java:
IRasterBand band = ((IRasterBandCollection)ras).item(0); IRawPixels pixels = new IRawPixelsProxy(band); IRasterProps properties = new IRasterPropsProxy(band);IRawPixels and IRasterProps are the only two that I ran into, but there may be more.
Bonus Tip: don't restart the server with debugging on
The extension debug settings are a huge help in tracking down errors in a Server Object Extension. However, they do not always play nice with some of the built-in Server functionality. In particular, the Map Publishing Service will often refuse to start up when debugging is enabled. If you need to restart your server, be sure to turn off extension debugging first.
Hopefully these pointers will help you avoid the same time-consuming mistakes that I made in porting my Server Object Extensions from C# to Java. Source code for my extensions in both languages is available in GitHub.