One maybe nonsense question: where does panConfidence4 come from? Are you
using an undeclared variable?

On Thu, Aug 13, 2026 at 7:24 PM Barry DeZonia <[email protected]> wrote:

> My foggy memory tells me that this looks good. I will let you and
> Even figure out the PR issue.
>
> On Thu, Aug 13, 2026 at 6:56 PM Tom Moore <[email protected]> wrote:
>
>> Thanks for offering to take a look.  I have a working draft already, but
>> I'm not sure if I'm taking the right approach and could use a review.
>>
>> The signature translation itself is the easy part.  The C# binding in
>> osr.i was an almost perfect example, and this is what I changed it to:
>>
>>     #ifdef SWIGJAVA
>>       OSRSpatialReferenceShadow** FindMatches( char** options, int*
>> nvalues, int** confidence_values )
>>       {
>>            return (OSRSpatialReferenceShadow**) OSRFindMatches(self,
>> options, nvalues, confidence_values);
>>       }
>>     #endif
>>
>> Everything interesting (haha, challenging) turned out to be in
>> typemaps_java.i, getting SWIG to actually expose that return value and the
>> two output parameters sensibly in Java.  I haven't used swig in a long
>> time, so I had forgotten most of the incantations.  Llm to the rescue.
>>
>> Here is the addition to typemaps_java.i:
>> == start ==
>> %typemap(in,numinputs=0) int* nvalues (int nMatches = 0)
>> {
>>   /* %typemap(in,numinputs=0) int* nvalues */
>>   $1 = &nMatches;
>> }
>>
>> %typemap(in) int** confidence_values (int* panConfidence = NULL)
>> {
>>   /* %typemap(in) int** confidence_values. Ignore the input,
>>      keep $input around so argout can write the real
>>      result into element [0]. */
>>   $1 = &panConfidence;
>> }
>>
>> %typemap(argout) int** confidence_values
>> {
>>   /* %typemap(argout) int** confidence_values will fill the caller's
>> int[][] */
>>   if ($input && jenv->GetArrayLength($input) >= 1) {
>>     jintArray confArray = jenv->NewIntArray(nMatches3);
>>     jenv->SetIntArrayRegion(confArray, 0, nMatches3,
>> (jint*)panConfidence4);
>>     jenv->SetObjectArrayElement($input, 0, confArray);
>>     jenv->DeleteLocalRef(confArray);
>>   }
>>   CPLFree(panConfidence4);
>> }
>>
>> %typemap(jni) int** confidence_values "jobjectArray"
>> %typemap(jtype) int** confidence_values "int[][]"
>> %typemap(jstype) int** confidence_values "int[][]"
>> %typemap(javain) int** confidence_values "$javainput"
>>
>> %typemap(out) (OSRSpatialReferenceShadow**)
>> {
>>   const jclass srsClass =
>> jenv->FindClass("org/gdal/osr/SpatialReference");
>>   const jmethodID srsCtor = jenv->GetMethodID(srsClass, "<init>",
>> "(JZ)V");
>>
>>   jresult = jenv->NewObjectArray(nMatches3, srsClass, NULL);
>>   for (int i = 0; i < nMatches3; i++) {
>>     OSRReference(result[i]);
>>     jobject srsObj = jenv->NewObject(srsClass, srsCtor, (jlong)result[i],
>> (jboolean)true);
>>     jenv->SetObjectArrayElement(jresult, i, srsObj);
>>     jenv->DeleteLocalRef(srsObj);
>>   }
>>   OSRFreeSRSArray(result);
>> }
>>
>> %typemap(jni) OSRSpatialReferenceShadow** "jobjectArray"
>> %typemap(jtype) OSRSpatialReferenceShadow**
>> "org.gdal.osr.SpatialReference[]"
>> %typemap(jstype) OSRSpatialReferenceShadow**
>> "org.gdal.osr.SpatialReference[]"
>> %typemap(javaout) OSRSpatialReferenceShadow** {
>>     return $jnicall;
>>   }
>> == end ==
>>
>> The nvalues argument stays hidden (numinputs=0), while confidence_values
>> becomes visible as an int[][] out-box, following the same
>> caller-passes-a-1-element-array-and-we-fill-it idiom already used elsewhere
>> in typemaps_java.i (the GDALDimensionHS** pattern was the model here).
>>
>> SWIG auto-suffixes typemap-declared local variables with the argument's
>> position in the full parameter list to avoid collisions.  FOr example, a
>> variable I declared as (int nMatches = 0) inside the nvalues typemap
>> (argument position 3) actually gets emitted into the generated code as
>> nMatches3, not nMatches. This isn't visible from the .i source at all, I
>> only found it by examining the generated osr_wrap.cpp after a failed
>> compile. Any other typemap block that needs to reference that same variable
>> (the argout/out blocks) has to hardcode the anticipated suffixed name
>> directly because SWIG doesn't rewrite references for you.
>>
>> End result:
>>
>>     public SpatialReference[] FindMatches(Vector options, int[][]
>> confidenceValuesOut)
>>
>> The function returns an array of matches (SpatialReference[] as
>> OSRSpatialReferenceShadow**), which is the primary thing that you want to
>> get from this function.
>>
>> How to use:
>>     int[][] confidence = new int[1][];
>>     SpatialReference[] matches = srs.FindMatches(null, confidence);
>>     int[] confidenceValues = confidence[0];
>>
>> Patched against the current master.  Tested on against an esri shapefile
>> .prj (ESRI-dialect NAD83 / UTM zone 11N WKT) that AutoIdentifyEPSG() fails
>> on with 'Unsupported SRS' -- FindMatches() correctly returns a single
>> match, EPSG:26911, with confidence[0][0] = 100, matching projinfo
>> --identify exactly on the same input.  Not tested any further than that.
>>
>> How does this look so far?  Is this going in the right direction?  If so,
>> what would it take to turn this into an acceptable PR?
>>
>> Thanks again for your help, and full disclosure, thanks to llm for
>> significant assistance on this.
>> Tom
>>
>> On Thu, Aug 13, 2026, at 5:16 PM, Barry DeZonia wrote:
>>
>> AI is helping me remember
>>
>> for the FindMatches() routine would you want it matching as close as
>> possible C types or would you want a simplified API for Java that mogt
>> communicate info via an array of strings (or one formatted string). Sorry
>> if that sounds out of left field.
>>
>> One AI said this:
>> 2. Handle Java JNI Typemaps
>> Because int** and object arrays (OSRSpatialReferenceShadow***) do not
>> map cleanly to standard Java types, you must ensure your SWIG configuration
>> or a companion helper helper translates them into manageable objects on the
>> Java side.
>> Alternatively, if dealing with direct pointer manipulation via SWIG
>> typemaps is too complex, developers routinely implement a *custom C++
>> wrapper function* inside osr.i that bundles the results into a string
>> format (such as an array of matching EPSG strings and confidences) before
>> passing it over the JNI boundary:
>>
>> swig
>>
>> %extend OSRSpatialReferenceShadow {
>>     // A simplified wrapper returning matches as formatted string arrays to 
>> avoid pointer hell
>>     char** FindMatchesSimple(char** options) {
>>         int nEntries = 0;
>>         int* panConfidence = NULL;
>>         OGRSpatialReferenceH* pahSRS = OGRSpatialReference_FindMatches(self, 
>> options, &nEntries, &panConfidence);
>>
>>         char** papszResult = NULL;
>>         // Construct a structured string array containing 
>> "EPSG:Code,Confidence"
>>         for(int i = 0; i < nEntries; i++) {
>>             const char* pszAuthName = 
>> OGRSpatialReference_GetAttrValue(pahSRS[i], "AUTHORITY", 0);
>>             const char* pszAuthCode = 
>> OGRSpatialReference_GetAttrValue(pahSRS[i], "AUTHORITY", 1);
>>             // Format string logic, append to papszResult...
>>             // BDZ - TODO - NOTE - This is the real work needed to finish 
>> this method.
>>         }
>>
>>         OSRFreeSRSArray(pahSRS);
>>         CPLFree(panConfidence);
>>         return papszResult;
>>     }
>> }
>>
>>
>> On Thu, Aug 13, 2026 at 3:08 PM Barry DeZonia <[email protected]> wrote:
>>
>> I could maybe help here but, good god, it's been a long time since I've
>> worked on the Java bindings and I remember almost nothing. Maybe if I
>> inspect the Java bindings code I will remember some stuff. Naively, the
>> function signature looks pretty simple to translate.
>>
>> On Thu, Aug 13, 2026 at 6:53 AM Even Rouault via gdal-dev <
>> [email protected]> wrote:
>>
>>
>> Tom,
>>
>> yes FindMatches() is what is needed for your use case and it is not
>> currently available in the Java bindings. That would require someone to
>> write the appropriate typemap(s) to map the C types to Java types.
>>
>> Even
>> Le 13/08/2026 à 13:15, Tom Moore via gdal-dev a écrit :
>>
>> Hi all,
>>
>> I'm running into a case where SpatialReference.AutoIdentifyEPSG() fails
>> on a completely standard, well-formed ESRI-dialect .prj file, even though
>> the underlying PROJ identification machinery (proj_identify(), as exercised
>> via "projinfo --identify") resolves it correctly with 100% confidence. I'd
>> like to know whether this is a known limitation, and whether there's a
>> recommended workaround for Java bindings users specifically, since
>> FindMatches() isn't exposed there.
>>
>> Environment:
>> - GDAL 3.11.1 (Windows build)
>> - PROJ 9.6.2
>> - Java bindings (org.gdal.osr / SWIG)
>>
>> Input WKT (contents of a shapefile .prj, ESRI dialect):
>>
>>
>> PROJCS["NAD_1983_UTM_Zone_11N",GEOGCS["GCS_North_American_1983",DATUM["D_North_American_1983",SPHEROID["GRS_1980",6378137.0,298.257222101]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]],PROJECTION["Transverse_Mercator"],PARAMETER["False_Easting",500000.0],PARAMETER["False_Northing",0.0],PARAMETER["Central_Meridian",-117.0],PARAMETER["Scale_Factor",0.9996],PARAMETER["Latitude_Of_Origin",0.0],UNIT["Meter",1.0]]
>>
>> QGIS correctly identifies this as EPSG:26911.
>>
>> What I tried (Java):
>>
>>     SpatialReference srs = new SpatialReference();
>>     srs.ImportFromESRI(lines);   // also tried plain ImportFromWkt() but
>> got the same result
>>     srs.SetAxisMappingStrategy(osrConstants.OAMS_TRADITIONAL_GIS_ORDER);
>>
>>     try {
>>         srs.AutoIdentifyEPSG();
>>     } catch (Exception ex) {
>>         System.out.println("Exception: " + ex.getMessage());
>>     }
>>     System.out.println("code = " + srs.GetAuthorityCode(null));
>>
>> Result:
>>
>>     Exception: OGR Error: Unsupported SRS
>>     code = null
>>
>> gdal.GetLastErrorType() / GetLastErrorMsg() are empty.  No additional
>> diagnostic detail is surfaced beyond the generic exception.
>>
>> I ruled out several things before suspecting this is a AutoIdentifyEPSG()
>> limitation rather than an environment/config issue on my end:
>>
>> 1. proj.db itself is correct.  Confirmed by mounting the exact same
>> proj.db (from the PROJ 9 data directory used by my JAva app) into a clean
>> ghcr.io/osgeo/gdal:ubuntu-small-latest container and running
>> `gdalsrsinfo -e` against the same .prj file. It resolved to EPSG:26911
>> correctly, full WKT2 with all authority IDs.
>> 2. PROJ_LIB / PROJ_DATA environment variables are set correctly and
>> confirmed using System.getenv() to be visible to the process
>> 3. Tried MorphFromESRI() (both via ImportFromESRI() alone, and combined
>> with an explicit MorphFromESRI() call) - no change.
>> 4. Tried explicit SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER)
>> before calling AutoIdentifyEPSG() - no change.
>> 5. Ran the projinfo.exe from the gdal build that I am using with the Java
>> app directly against the same .prj file:
>>
>>     projinfo.exe --identify fmu.prj
>>     ...
>>     Identification match count: 1
>>     EPSG:26911: 100 %
>>
>> So proj_identify() / FindMatches()-equivalent logic resolves this WKT
>> perfectly in the exact same native build, but AutoIdentifyEPSG() fails on
>> it.
>>
>> This looks consistent with a few things I found in the tracker/mailing
>> list archives while investigating:
>>
>> - https://trac.osgeo.org/gdal/ticket/6188 -- maintainer comment noting
>> AutoIdentifyEPSG() has "very limited capabilities" and would need fuzzy
>> matching to handle inexact datum/ellipsoid names, "especially when dealing
>> with WKT coming from ESRI."
>> - https://github.com/OSGeo/gdal/issues/4038 -- near-identical repro WKT
>> (ESRI-dialect UTM), with a maintainer noting AutoIdentifyEPSG() can return
>> OGRERR_UNSUPPORTED_SRS while having still injected partial AUTHORITY tags
>> into sub-nodes.  This matches what I see when printing the WKT after the
>> failed call (DATUM gets EPSG:6269, but the top-level PROJCS never gets
>> an ID).
>> - https://github.com/OSGeo/gdal/issues/2303 -- shows the standard Python
>> workaround (fall back to FindMatches() when AutoIdentifyEPSG() fails),
>> which leads to my second question below.
>>
>> Questions:
>>
>> 1. Is AutoIdentifyEPSG() failing on this ESRI-dialect NAD83/UTM WKT a
>> known limitation, or does this look like a genuine regression/bug worth
>> filing?
>> 2. FindMatches() does not appear to be exposed in the Java SWIG bindings
>> (org.gdal.osr.SpatialReference).  Is that correct, or am I missing
>> something? If it's genuinely absent, is there any appetite for adding it,
>> given it's the documented fallback for exactly this situation in other
>> language bindings?
>> 3. Short of shelling out to "projinfo --identify" as a subprocess, is
>> there a recommended in-process approach for Java bindings users to reach
>> the same identification logic?
>>
>> Happy to provide a minimal reproducible test case / file a tracker issue
>> if that's useful, but I wanted to check here first in case this is already
>> understood behavior.
>>
>> Thanks,
>> Tom
>>
>>
>> _______________________________________________
>> gdal-dev mailing 
>> [email protected]https://lists.osgeo.org/mailman/listinfo/gdal-dev
>>
>> -- http://www.spatialys.com
>> My software is free, but my time generally not.
>> LLMs contribute to global warming and brain rot.
>> Let's guillotine them! "Ah ! ça ira, ça ira, ça ira !"
>>
>> _______________________________________________
>> gdal-dev mailing list
>> [email protected]
>> https://lists.osgeo.org/mailman/listinfo/gdal-dev
>>
>>
>> --
>> Tom Moore
>> Spatial Planning Systems
>> 960 Burkes Bluff Lane
>> Deep River ON  K0J 1P0
>> Canada
>>
>> Phone: +1 613 584 9354
>>
>>
_______________________________________________
gdal-dev mailing list
[email protected]
https://lists.osgeo.org/mailman/listinfo/gdal-dev

Reply via email to