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