Programming with ArcObjects  

Casting and run time type checking (using instanceof)

ArcObjects follows an interface-based programming style. Many methods use interface types as parameters and have interfaces as return values. When the return value of a method is an interface type, the method returns an object implementing that interface. When a method takes an interface type as a parameter, it can take in any object implementing that interface. This style of programming has the advantage that the same method can work with many different object types that implement the required interface.

In this article, learn about:


In the Java programming language, the casting/coercing operation is used to convert between types and the instanceof operator is used to check for type information at run time. ArcGIS 9.2 Java products provide a greater support for Java-style casting and instanceof operations than prior releases. (The old style of casting and run time checks using the single valued constructors of IxxxProxy() type classes will still be supported for backward compatibility).


The usage of these operations in the context of ArcObjects Java programming is explained by the following example:


Consider the IFeature.getShape() method that returns an object implementing the IGeometry interface. The object returned could potentially be any one of the following concrete classes that implement IGeometry: BezierCurve, CircularArc, EllipticArc, Envelope, GeometryBag, Line, MultiPatch, Multipoint, Path, Point, Polygon, Polyline, Ray, Ring, Sphere, TriangleFan, Triangles, or TriangleStrip.


There are three types of potential casts you may wish to perform with the ArcGIS Java API classes (the example below uses Point as the underlying object):

  1. Interface to concrete class casting (IGeometry to Point)
  2. Interface cross casting (IPoint to IZAware)
  3. Interface down casting (IGeometry to IPoint)

 

You might also want to know which of the specific concrete class types was returned by the IFeature.getShape() method for which the instanceof operator could be used. These concepts are best described by examples that compare the two styles (old and new) of casting and performing run time checks while programming ArcObjects Java.


Old style of casting:

IFeature feature = featureClass.getFeature(i);
//Assume that the underlying feature was either a Point or a Polygon
IGeometry geom = feature.getShape();
try{
 Point p = new Point(geom);
 // One reason for the following method's failure would be if geom is
 // not a Point
 p.setX(value); Point
}
catch(Exception e){
 try{
  // p.setX(value) failed possibly because geom is not of type Point.
  // Try Polygon
  Polygon poly = new Polygon(geom);
  poly.getArea(); // This should succeed if the geom is a Polygon
 }
 catch(Exception e){
  e.printStackTrace();
 }
}

New style of casting and run time checks:

IFeature feature = featureClass.getFeature(i);
//Assume that the underlying feature was either a Point or a Polygon
IGeometry geom = feature.getShape();
if(geom instanceof Polygon)
	Polygon polygon = (Polygon)geom;
else if(geom instanceof Point)
	Point point = (Point)geom;


In the new style of casting, a full-fledged Point object was precasted and returned back as the result of the feature.getShape(). ESRI's interoperability bridge (which facilitates communication between the native ArcObjects runtime and the Java runtime environment) contains the logic for performing this precasting operation on the return value to hand back a concrete object that implements the interface to be returned in addition to other relevant interfaces on that object (IPoint, IZAware, etc, on a Point object).


Working with workspaces
The concept of a workspace is central to any application that works with geographic data. The ArcGIS Java API provides support for working with approximately 16 different types of workspaces (ShapefileWorkspace, RasterWorkspace, etc). The workspace implementation in native ArcObjects follows the abstract factory pattern. The result is that a user opening a workspace through a workspace factory gets an interface (IWorkspace) on that underlying workspace that was created. In prior releases, what followed was either a proxy style cast to an interface on the Workspace class or the creation of the Workspace class by passing a reference to the IWorkspace interface, then casting to the required interface (e.g. IDataset).
The Workspace class exposes a collection of generic interfaces and operations that are supported by all the typed workspace implementations. At ArcGIS Java 9.2 release, the return value of each method used to open a workspace (IWorkspaceFactory.open(), IWorkspaceFactory.openFromFile(), or IWorkspaceFactory2.openFromString()) will be wrapped in an instance of the Workspace class so that switching between interfaces on the Workspace class (IWorkspace, IDataset, etc.) could be performed using Java's language support for casting.

 

The following are the usage patterns that could be employed:

ShapefileWorkspaceFactory shpWksFactory = new  ShapefileWorkspaceFactory();
// Usage 1
IFeatureWorkspace ws =  (IFeatureWorkspace)shpWksFactory.openFromFile("\path\to\workspace",0);
// Usage 2
Workspace ws =  shpWksFactory.openFromFile("\path\to\workspace",0);
IFeatureWorkspace fws = (IFeatureWorkspace)ws;
// Usage 3
IWorkspace ws =  shpWksFactory.openFromFile("\path\to\workspace",0);
IFeatureWorkspace fws = (IFeatureWorkspace)ws;

 

Please note that you would still need to use proxy style casts to access interfaces other than the ones present on the Workspace class. For example, opening a RasterWorkspace and getting an IRasterWorkspace would need a proxy cast as explained below:

 

RasterWorkspaceFactory rstrWksFactory = new  RasterWorkspaceFactory();
Workspace ws =  rstrWksFactory.open("\path\to\workspace",0);
// IRasterWorkspace is not implemented by Workspace
IRasterWorkspace rasterWs = new IRasterWorkspaceProxy(ws);  


Classes that cannot be cast to
In the ArcGIS Java API, the return values of certain methods cannot be cast to a particular category of types. Types/classes that belong to this category are, FeatureClass, FeatureCursor, FeatureDataset, RelQueryTable, Table, etc. The definition for these classes in the ArcGIS Java API documentation reveals that they only have a single argument constructor but no empty constructor. Such classes are designed to be abstract classes or concept types of classes in the ArcObjects object model specification. A FeatureClass, for example, can be thought of as a concept that models a finite set of spatial features. Internal to ArcObjects, there could be several different implementations of the notion of a feature class. Hence FeatureClass does not directly map to one particular underlying implementation of a feature class (as opposed to a Point class in the Java API that parallels a Point class in native ArcObjects). The purpose of exposing the FeatureClass (and other classes in this category) in the Java API is to provide the user with the knowledge of a set of generic interfaces that every concrete implementation of such an abstract class would minimally support.

 
IWorkspaceFactory wf = new ShapefileWorkspaceFactory();
 IFeatureWorkspace fw = new IFeatureWorkspaceProxy(wf.openFromFile("\path\to\data", 0))
 
// THIS WILL NOT WORK!! Will throw java.lang.ClassCastException
 FeatureClass fc = (FeatureClass)fw.openFeatureClass("featureclass name");
 
// THE CORRECT WAY
IFeatureClass fc = fw.openFeatureClass("featureclass name");
FeatureClass featureClass = new FeatureClass(fc);
        OR

// THE CORRECT WAY (USING OLD PROXY STYLE CASTING)
IFeatureClass fc = fw.openFeatureClass("featureclass name");
IGeoDataset gds = new IGeoDatasetProxy(fc);

The example shows that return values of methods like fw.openFeatureClass() will not be precast into any of the candidate classes—FeatureClass, NAClass, RasterCatalog, RelQueryTable, RouteEventSource, or XYEventSource—that implement the returned interface because the internal ArcObjects classes implementing these abstract classes are private and not exposed through the API. In situations like these, you need to use the old proxy style casting to switch between interfaces that you expect on a candidate class (e.g., from IFeatureClass to IGeoDataset) or create a new full-fledged instance of such a class using its single argument constructor (featureClass = new FeatureClass(fc)), then work with the interfaces on them as demonstrated in the example.

 

Provided below is a final example that summarizes the concepts presented in this article. The example opens a ShapefileWorkspace and retrieves a feature from a feature class.

ShapefileWorkspaceFactory shpWksFactory = new ShapefileWorkspaceFactory();
IFeatureWorkspace fws = (IFeatureWorkspace)shpWksFactory.openFromFile("\path\to\workspace",0);

// this will print "true"
System.out.println((fws instanceof Workspace));
IFeatureClass featureClass = fws.openFeatureClass("feature class");

// old style casting needed here
ITable table = new ITableProxy(featureClass);
int numRows = table.rowCount(null);

// This method will return a concrete object that models the underlying // geometry/feature (assume either Point/Polygon)
IGeometry geom = featureClass.getFeature(i);

if(geom instanceof Point)
	doSomethingWithPoint();
else if(geom Instanceof Polygon)
	doSomethingWithPolygon();

The following is a list of those classes that cannot be cast to:

com.esri.arcgis.carto.AnnotationElement
com.esri.arcgis.carto.AnnotationExpressionParser
com.esri.arcgis.carto.BasicPlacedObject
com.esri.arcgis.carto.esriGpsDateTime
com.esri.arcgis.carto.esriGpsDgpsInfo
com.esri.arcgis.carto.esriGpsDOPInfo
com.esri.arcgis.carto.esriGpsGroundCourse
com.esri.arcgis.carto.esriGpsMagneticVariance
com.esri.arcgis.carto.esriGpsPositionInfo
com.esri.arcgis.carto.esriGpsSatelliteData
com.esri.arcgis.carto.FDOGraphicsSublayer
com.esri.arcgis.carto.GraphicsSubLayer
com.esri.arcgis.carto.IKMLServer
com.esri.arcgis.carto.IMSSubFeatureLayer
com.esri.arcgis.carto.IMSSubLayer
com.esri.arcgis.carto.KMLServer
com.esri.arcgis.carto.MapSelection
com.esri.arcgis.carto.MapServerBasicSublayer
com.esri.arcgis.carto.MapServerFindSublayer
com.esri.arcgis.carto.MapServerIdentifySublayer
com.esri.arcgis.carto.MapServerQuerySublayer
com.esri.arcgis.carto.RasterFormatInfo
com.esri.arcgis.carto.RasterIdentifyObj
com.esri.arcgis.carto.RasterRGBSymbol
com.esri.arcgis.carto.SimpleRasterIdentifyObj
com.esri.arcgis.carto.WMSGroupLayer
com.esri.arcgis.carto.WMSLayer

com.esri.arcgis.datasourcesfile.ICadDrawingDataset
com.esri.arcgis.datasourcesfile.ILicensedDataExtension
com.esri.arcgis.datasourcesfile.ILicensedUnitInfo
com.esri.arcgis.datasourcesfile.ILicensedUnits
com.esri.arcgis.datasourcesfile.SMDirections
com.esri.arcgis.datasourcesfile.SMDirItem
com.esri.arcgis.datasourcesfile.SMFlag
com.esri.arcgis.datasourcesfile.SMFlagCreator
com.esri.arcgis.datasourcesfile.SMNetAttribute
com.esri.arcgis.datasourcesfile.SMNetAttributesAccess
com.esri.arcgis.datasourcesfile.SMNetAttributesCollection
com.esri.arcgis.datasourcesfile.SMNetBarriersCollection
com.esri.arcgis.datasourcesfile.SMPointsCollection
com.esri.arcgis.datasourcesfile.SMRoadPreferences
com.esri.arcgis.datasourcesfile.SMRouter
com.esri.arcgis.datasourcesfile.SMRouterEnvelope
com.esri.arcgis.datasourcesfile.SMSpeedGroup
com.esri.arcgis.datasourcesfile.SMSpeedGroups
com.esri.arcgis.datasourcesfile.SMTripPlanSettings

com.esri.arcgis.datasourcesraster.IMemoryRasterDataset
com.esri.arcgis.datasourcesraster.IRasterMapModel2
com.esri.arcgis.datasourcesraster.IRasterStatusEvent2Adapter
com.esri.arcgis.datasourcesraster.IRasterStatusEvent2Esri_continueEvent
com.esri.arcgis.datasourcesraster.IRasterStatusEvent2MessageEvent
com.esri.arcgis.datasourcesraster.IRasterStatusEvent2TitleEvent
com.esri.arcgis.datasourcesraster.IRasterStatusEventAdapter
com.esri.arcgis.datasourcesraster.IRasterStatusEventStartEvent
com.esri.arcgis.datasourcesraster.IRasterStatusEventStepEvent
com.esri.arcgis.datasourcesraster.IRasterStatusEventStopEvent
com.esri.arcgis.datasourcesraster.PixelBlock
com.esri.arcgis.datasourcesraster.RasterBand
com.esri.arcgis.datasourcesraster.RasterBands
com.esri.arcgis.datasourcesraster.RasterCursor
com.esri.arcgis.datasourcesraster.RasterNativeType
com.esri.arcgis.datasourcesraster.RasterStatusEvent2Helper
com.esri.arcgis.datasourcesraster.RasterStatusEventHelper
com.esri.arcgis.datasourcesraster.RasterWorkspace

com.esri.arcgis.display.esriGDICommentBeginGroup
com.esri.arcgis.display.esriGDICommentBeginLayer
com.esri.arcgis.display.esriGDICommentBeginText
com.esri.arcgis.display.esriGDICommentBeginTextEx
com.esri.arcgis.display.esriGDICommentEndGroup
com.esri.arcgis.display.esriGDICommentEndLayer
com.esri.arcgis.display.esriGDICommentEndText
com.esri.arcgis.display.esriGDICommentFillWithPattern
com.esri.arcgis.display.esriGDICommentMaskLayer
com.esri.arcgis.display.esriGDICommentMaskLayerBeforeClipping
com.esri.arcgis.display.esriGDICommentPlayEnhMetafileBegin
com.esri.arcgis.display.esriGDICommentPlayEnhMetafileEnd
com.esri.arcgis.display.esriGDICommentSetCmykColor
com.esri.arcgis.display.esriGDICommentSetTextExtra
com.esri.arcgis.display.esriGDICommentSetTextJustification
com.esri.arcgis.display.GeometricEffectPathToRing
com.esri.arcgis.display.tagCONNECTDATA com.esri.arcgis.display.tagPOINT
com.esri.arcgis.display.tagRECT

com.esri.arcgis.geodatabase.AttributedRelationshipClass
com.esri.arcgis.geodatabase.ConfigurationKeyword
com.esri.arcgis.geodatabase.ConfigurationParameter
com.esri.arcgis.geodatabase.Cursor
com.esri.arcgis.geodatabase.DddServerEnvironment
com.esri.arcgis.geodatabase.DifferenceCursor
com.esri.arcgis.geodatabase.EnumConflictClass
com.esri.arcgis.geodatabase.EnumDatasetType
com.esri.arcgis.geodatabase.EnumFieldError
com.esri.arcgis.geodatabase.EnumHistoricalMarker
com.esri.arcgis.geodatabase.EnumIDs
com.esri.arcgis.geodatabase.EnumInvalidObject
com.esri.arcgis.geodatabase.EnumNetWeightAssociation
com.esri.arcgis.geodatabase.EnumNetworkElement
com.esri.arcgis.geodatabase.EnumVersionInfo
com.esri.arcgis.geodatabase.EnumXMLIndexTemplate
com.esri.arcgis.geodatabase.FeatureClass
com.esri.arcgis.geodatabase.FeatureCursor
com.esri.arcgis.geodatabase.FeatureDataset
com.esri.arcgis.geodatabase.FieldError com.esri.arcgis.geodatabase.ForwardStar
com.esri.arcgis.geodatabase.HistoricalVersionMarker
com.esri.arcgis.geodatabase.IConflictResolverHelper
com.esri.arcgis.geodatabase.IFeatureProgressAdapter
com.esri.arcgis.geodatabase.IFeatureProgressIsCancelledEvent
com.esri.arcgis.geodatabase.IFeatureProgressSetFeatureClassNameEvent
com.esri.arcgis.geodatabase.IFeatureProgressSetMaxFeaturesEvent
com.esri.arcgis.geodatabase.IFeatureProgressSetMinFeaturesEvent
com.esri.arcgis.geodatabase.IFeatureProgressSetPositionEvent
com.esri.arcgis.geodatabase.IFeatureProgressSetStepValueEvent
com.esri.arcgis.geodatabase.IFeatureProgressStepEvent
com.esri.arcgis.geodatabase.InvalidObjectInfo
com.esri.arcgis.geodatabase.IRepresentationOutline
com.esri.arcgis.geodatabase.MemoryRelationshipClass
com.esri.arcgis.geodatabase.NetElementClass
com.esri.arcgis.geodatabase.NetworkDataset
com.esri.arcgis.geodatabase.NetworkDatasetFDExtension
com.esri.arcgis.geodatabase.NetworkDatasetWorkspaceExtension
com.esri.arcgis.geodatabase.NetworkEdge
com.esri.arcgis.geodatabase.NetworkForwardStar
com.esri.arcgis.geodatabase.NetworkForwardStarAdjacencies
com.esri.arcgis.geodatabase.NetworkJunction
com.esri.arcgis.geodatabase.NetworkTurn
com.esri.arcgis.geodatabase.NetworkWorkspace
com.esri.arcgis.geodatabase.ObjectClass com.esri.arcgis.geodatabase.QueryDef
com.esri.arcgis.geodatabase.RasterCatalog
com.esri.arcgis.geodatabase.Relationship
com.esri.arcgis.geodatabase.RelationshipClass
com.esri.arcgis.geodatabase.RelQueryCursor
com.esri.arcgis.geodatabase.RelQueryRow
com.esri.arcgis.geodatabase.RelQueryTable
com.esri.arcgis.geodatabase.RelQueryTableSelectionSet
com.esri.arcgis.geodatabase.ReplicaDescriptionExtension
com.esri.arcgis.geodatabase.Representation
com.esri.arcgis.geodatabase.RepresentationClass
com.esri.arcgis.geodatabase.RowBuffer com.esri.arcgis.geodatabase.SelectionSet
com.esri.arcgis.geodatabase.StreetNetwork
com.esri.arcgis.geodatabase.SystemJunctionSource
com.esri.arcgis.geodatabase.Table
com.esri.arcgis.geodatabase.tagesriTopologyParent
com.esri.arcgis.geodatabase.tagFieldValue
com.esri.arcgis.geodatabase.TinEdgeArray
com.esri.arcgis.geodatabase.TinEdgeEnumerator
com.esri.arcgis.geodatabase.TinNodeArray
com.esri.arcgis.geodatabase.TinNodeEnumerator
com.esri.arcgis.geodatabase.TinPolygon com.esri.arcgis.geodatabase.TinPolyline
com.esri.arcgis.geodatabase.TinSurfaceElement
com.esri.arcgis.geodatabase.TinTriangleArray
com.esri.arcgis.geodatabase.TinTriangleEnumerator
com.esri.arcgis.geodatabase.TopologyEdge
com.esri.arcgis.geodatabase.TopologyErrorFeature
com.esri.arcgis.geodatabase.TopologyGraph
com.esri.arcgis.geodatabase.TopologyNode
com.esri.arcgis.geodatabase.UtilityNetwork
com.esri.arcgis.geodatabase.VersionedWorkspace
com.esri.arcgis.geodatabase.VersionInfo com.esri.arcgis.geodatabase.Workspace
com.esri.arcgis.geodatabase.WorkspaceExtension
com.esri.arcgis.geodatabase.WorkspaceFactory
com.esri.arcgis.geodatabase.XYEventSource

com.esri.arcgis.geodatabasedistributed.DataChanges
com.esri.arcgis.geodatabasedistributed.IOperationProgressAdapter
com.esri.arcgis.geodatabasedistributed.IOperationProgressSetCurrentOperationEvent
com.esri.arcgis.geodatabasedistributed.IOperationProgressSetObjectCountEvent
com.esri.arcgis.geodatabasedistributed.IOperationProgressSetOperationsEvent
com.esri.arcgis.geodatabasedistributed.IOperationProgressStartupEvent
com.esri.arcgis.geodatabasedistributed.IReplicaProgressAdapter
com.esri.arcgis.geodatabasedistributed.IReplicaProgressSetCurrentReplicaOperationEvent
com.esri.arcgis.geodatabasedistributed.IReplicaProgressSetReplicaObjectCountEvent
com.esri.arcgis.geodatabasedistributed.IReplicaProgressSetReplicaOperationsEvent
com.esri.arcgis.geodatabasedistributed.IReplicaProgressStartupEvent
com.esri.arcgis.geodatabasedistributed.OperationProgress
com.esri.arcgis.geodatabasedistributed.ReplicaProgress

com.esri.arcgis.geometry._esriSegmentInfo com.esri.arcgis.geometry._WKSPointVA
com.esri.arcgis.geometry.esriGeometryNetworkVertexInfo
com.esri.arcgis.geometry.esriOriginalSegmentMapping
com.esri.arcgis.geometry.esriSRHorizon

com.esri.arcgis.geostatisticalanalyst.GAStatusEvent
com.esri.arcgis.geostatisticalanalyst.IGAStatusEventAdapter
com.esri.arcgis.geostatisticalanalyst.IGAStatusEventProgressContinueEvent
com.esri.arcgis.geostatisticalanalyst.IGAStatusEventProgressEndEvent
com.esri.arcgis.geostatisticalanalyst.IGAStatusEventProgressStartEvent
com.esri.arcgis.geostatisticalanalyst.IGAStatusEventProgressStepEvent

com.esri.arcgis.location.AGSAddressLocator
com.esri.arcgis.location.AGSLocatorWorkspace
com.esri.arcgis.location.AttachedLocator
com.esri.arcgis.location.DatabaseLocatorWorkspace
com.esri.arcgis.location.ESRIFDOAddressLocator
com.esri.arcgis.location.ESRIFDOAddressLocatorStyle
com.esri.arcgis.location.LocalLocatorWorkspace
com.esri.arcgis.location.LocatorEnumerator
com.esri.arcgis.location.LocatorNameEnumerator
com.esri.arcgis.location.ReferenceDataField
com.esri.arcgis.location.ReferenceDataFieldsEnumerator
com.esri.arcgis.location.ReferenceDataIndex
com.esri.arcgis.location.ReferenceDataIndexEnumerator
com.esri.arcgis.location.ReferenceDataTable
com.esri.arcgis.location.ReferenceDataTableEnumerator
com.esri.arcgis.location.RouteEventSource
com.esri.arcgis.location.RouteMeasureLocator
com.esri.arcgis.location.StreetMapAddressLocator
com.esri.arcgis.location.StreetMapAddressLocatorStyle

com.esri.arcgis.networkanalysis.EIDInfo
com.esri.arcgis.networkanalysis.EnumEIDInfo
com.esri.arcgis.networkanalysis.INetworkLoaderProgressAdapter
com.esri.arcgis.networkanalysis.INetworkLoaderProgressIsCancelledEvent
com.esri.arcgis.networkanalysis.INetworkLoaderProgressPutMessageEvent
com.esri.arcgis.networkanalysis.INetworkLoaderProgressSetMaxFeaturesEvent
com.esri.arcgis.networkanalysis.INetworkLoaderProgressSetStepValueEvent
com.esri.arcgis.networkanalysis.INetworkLoaderProgressStepEvent
com.esri.arcgis.networkanalyst.esriNALayerType
com.esri.arcgis.networkanalyst.NAClass com.esri.arcgis.server.ServerCluster

com.esri.arcgis.server.ServerCluster$ServerInfo
com.esri.arcgis.server.ServerClusterType com.esri.arcgis.server.ServerContext
com.esri.arcgis.server.ServerDirectory
com.esri.arcgis.server.ServerDirectoryInfo com.esri.arcgis.server.ServerLogImpl
com.esri.arcgis.server.ServerMachine com.esri.arcgis.server.ServerMachineStatus
com.esri.arcgis.server.ServerObject com.esri.arcgis.server.ServerObjectAdmin
com.esri.arcgis.server.ServerObjectConfiguration
com.esri.arcgis.server.ServerObjectConfigurationInfo
com.esri.arcgis.server.ServerObjectConfigurationStatus
com.esri.arcgis.server.ServerObjectExtensionType
com.esri.arcgis.server.ServerObjectExtensionTypeInfo
com.esri.arcgis.server.ServerObjectManager
com.esri.arcgis.server.ServerObjectType
com.esri.arcgis.server.ServerObjectTypeInfo
com.esri.arcgis.server.ServerStatisticsArray
com.esri.arcgis.server.ServerStatisticsResults

com.esri.arcgis.system._esriPointAttributes
com.esri.arcgis.system._esriPointAttributesEx
com.esri.arcgis.system._esriSegmentModifier com.esri.arcgis.system._FILETIME
com.esri.arcgis.system._LARGE_INTEGER com.esri.arcgis.system._ULARGE_INTEGER
com.esri.arcgis.system._WKSEnvelope com.esri.arcgis.system._WKSPoint
com.esri.arcgis.system._WKSPointZ com.esri.arcgis.system.EngineInitializer
com.esri.arcgis.system.ServerInitializer com.esri.arcgis.system.tagSTATSTG

com.esri.arcgis.terrain.DynamicSurface com.esri.arcgis.terrain.Terrain
com.esri.arcgis.terrain.TerrainEnumerator
com.esri.arcgis.terrain.TerrainFeatureDatasetExtension