jenetics/jpx

Can't read file if it contains any extension tag

TheNatanx opened this issue · 7 comments

Hello,

I am currently trying to use your lib to encode and decode GPX files. I am running into a problem whenever I want to read any file containing extensions tags. As soon as the tag is removed, the parser can properly read the file without any difficulty. I get the “java.io.InvalidObjectException: Invalid 'gpx' input.”.
I tried using GPX files generated by software such as MapSource (see exemple xml file below) and ultimately I resorted to try using xml files yourself used in your tests such as jpx/src/test/resources/io/jenetics/jpx/extensions-waypoint.gpx and it still does not work.
The code I wrote in to read the file is the following:

try {
            GPX gpx = GPX.read(pastString);
            List<WayPoint> list = gpx.getWayPoints();

            for (WayPoint wayPoint : list) {
                log.info(String.valueOf(wayPoint.getName()));
                log.info(String.valueOf(wayPoint.getComment()));
                log.info(String.valueOf(wayPoint.getLatitude().toDegrees()));
                log.info(String.valueOf(wayPoint.getLongitude().toDegrees()));
                log.info(String.valueOf(wayPoint.getElevation()));
                log.info(String.valueOf(wayPoint.getSymbol()));
            }
        } catch (IOException e) {
            log.error(String.valueOf(e));
        }

At this point I am wondering if this a bug? if I am doing something wrong? and whether if it is possible to simply ignore the extension tags whenever I want to read a file.

Hopefully you can help me out 😊

My XML File
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<gpx xmlns="http://www.topografix.com/GPX/1/1" creator="MapSource 6.16.3" version="1.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd">

 <metadata>
   <link href="http://www.garmin.com">
     <text>Garmin International</text>
   </link>
   <time>2020-11-25T13:38:53Z</time>
   <bounds maxlat="46.725824140012264" maxlon="1.085954681038857" minlat="46.725824140012264" minlon="1.085954681038857"/>
 </metadata>

 <wpt lat="46.725824140012264" lon="1.085954681038857">
   <ele>85</ele>
   <time>2020-11-25T13:38:27Z</time>
   <name>TESTTOS</name>
   <cmt>azertyy</cmt>
   <desc>azertyy</desc>
   <sym>Flag, Blue</sym>
   <extensions>
       <Proximity>2000</Proximity>
       <Temperature>25</Temperature>
       <Depth>45</Depth>
       <DisplayMode>SymbolAndName</DisplayMode>
       <Address>
         <StreetAddress>az</StreetAddress>
         <City>er</City>
         <State>rt</State>
         <Country>France</Country>
         <PostalCode>45000</PostalCode>
       </Address>
       <PhoneNumber>0606060606</PhoneNumber>
   </extensions>
 </wpt>
 
</gpx>

Hi @TheNatanx,

I'm able to parse the given file.

@Test
public void issue137_Parsing() throws IOException {
    final String resource = "/io/jenetics/jpx/ISSUE-137.gpx";

    final GPX gpx;
    try (InputStream in = getClass().getResourceAsStream(resource)) {
        gpx = GPX.read(in);
    }

    final var ext = gpx.getWayPoints().get(0).getExtensions();
    ext.ifPresent(doc ->
        System.out.println(XML.toString(doc))
    );
}

And it prints out the content of the extension. I run it with Java 11 with the latest library version 2.1. Can you tell me which version are you using, the OS and the full stack-trace of your error?

Well I am running the latest 2.1 version of the library on Windows 10. As of the stacktrace, there is only this one line i mentionned before "java.io.InvalidObjectException: Invalid 'gpx' input".

By the way, I am not able to execute your code as of the following message "'io.jenetics.jpx.XML' is not public in 'io.jenetics.jpx'. Cannot be accessed from outside package".

And, to conclude with, if i try using this piece of code on the same file i get a "java.io.InvalidObjectException: Null InputStream is not a valid argument" error :

final GPX gpx;
try (InputStream in = getClass().getResourceAsStream(s)) {
	gpx = GPX.read(in);
}

List<WayPoint> list = gpx.getWayPoints();

for (WayPoint wayPoint : list) {
	log.info(String.valueOf(wayPoint.getName()));
	log.info(String.valueOf(wayPoint.getComment()));
	log.info(String.valueOf(wayPoint.getLatitude().toDegrees()));
	log.info(String.valueOf(wayPoint.getLongitude().toDegrees()));
	log.info(String.valueOf(wayPoint.getElevation()));
	log.info(String.valueOf(wayPoint.getSymbol()));
}

Okay, ultimately I found were it can be mixed up. I am using other libs alongside yours and one seems to interfere with the XML provider because I get this error javax.xml.transform.TransformerException: Unable to transform a source of type javax.xml.transform.stax.StAXSource

Is there anyway to overide it to get back to the original provider ? I would appreciate any advice from you.
I found that it may be related to another lib trying to handle XMLs and could cause a direct or indirect conflict : the woodstox library (https://github.com/FasterXML/woodstox)

Maybe implementing your own XMLProvider class will help. It's based on the service loader mechanism of Java.

Okay, i just don't understand fully the part about the META-INF file an how to define/use it.

Create a class and extend from the XMLProvider class of the JPX library.

package com.mypackage;
class MyXMLProvider extends XMLProvider {
   @Override
   public DocumentBuilderFactory documentBuilderFactory() {
      // Configure your own document builder factory.
      return ...;
   }
}

Create a file META_INF/services/io.jenetics.jpx.XMLProvider, in the resources folder of your project (if you are using the usual maven layout), with the following content:

com.mypackage.MyXMLProvider

The JPX library will now load and use your MyXMLProvider and use the DocumentBuilderFactory, created by your implementation, for parsing the extensions.

It might also be necessary to override the xmlInputFactory method.