1

Here is my Java code that generates an error from Geotools renderer:

public class LandmarkLayer {
protected static final String LANDMARK_FEATURE_NAME = "landmark";
protected static final StyleFactory SF = CommonFactoryFinder.getStyleFactory();
protected static final FilterFactory2 FF = CommonFactoryFinder.getFilterFactory2();
protected static final Color LANDMARK_COLOR = new Color(0, 0, 160);
// Tower icon
protected static final String TOWER_ICON_PATH = "landmarks/water_tower.svg";
protected static final float POINT_SIZE = 10.0f;

public static Layer createLayer(DataStore dataStore) {
 // category == 17 <==> tower
    PropertyIsEqualTo piet = FF.equals(FF.property("category"),
                                       FF.literal(17)         );
    Rule towerRule = SF.createRule();
    towerRule.setName("rule for tower landmarks");
    towerRule.setFilter(piet);

    OnLineResourceImpl svgTower = null;
    try {
        svgTower = new OnLineResourceImpl(new URI(TOWER_ICON_PATH));
    } catch (URISyntaxException ex) {
        System.out.flush();
        System.err.println("Syntax error in next tower icon path : " +
                           TOWER_ICON_PATH);
        System.exit(1);
    }
    svgTower.freeze(); // freeze to prevent modification at runtime
 // List of symbols is considered in order with the rendering engine
 // choosing the first one it can handle. Here only two choices are
 // possible: svg or small circle
    List<GraphicalSymbol> symbols = new ArrayList<>();

    symbols.add(SF.externalGraphic(svgTower, "svg", null));

 // simple circle backup plan
    Stroke stroke = SF.stroke(FF.literal("#000000"),
                              null                 ,
                              null                 ,
                              null                 ,
                              null                 ,
                              null                 ,
                              null                 );
    Fill fill = SF.fill(null                  ,
                        FF.literal(Color.BLUE),
                        FF.literal(1.0f)      );
 // create the graphical mark used to represent a tower
    symbols.add(SF.mark(FF.literal("tower"), fill, stroke)); 

    Expression opacity = null; // use default
    Expression size = FF.literal(POINT_SIZE);
    Expression rotation = null; // use default
    AnchorPoint anchor = null; // use default
    Displacement displacement = null; // use default

 // define a point symbolizer for towers
    Graphic towerSymbols = SF.graphic
                   (symbols, opacity, size, rotation, anchor, displacement);
    PointSymbolizer pointSymbolizer = SF.pointSymbolizer
                                           ("tower"            ,
                                            FF.property("geom"),
                                            null               ,
                                            null               ,
                                            towerSymbols       );
    towerRule.symbolizers().add(pointSymbolizer);

    FeatureTypeStyle featureTypeStyle = SF.createFeatureTypeStyle();
    featureTypeStyle.rules().add(towerRule);
    Style style = SF.createStyle();
    style.featureTypeStyles().add(featureTypeStyle);

    SimpleFeatureSource featureSource = null;
    try {
        featureSource = dataStore.getFeatureSource(LANDMARK_FEATURE_NAME);
    } catch (IOException ex) {
        System.out.flush();
        System.err.println("Unable to find the feature called " + 
                           LANDMARK_FEATURE_NAME + " in database");
        System.exit(1);
    }

    Layer layer = new FeatureLayer(featureSource, style);

    return layer;
}

And here is the error message at runtime:

GRAVE: ExternalGraphic location URL cannot be null
java.lang.IllegalArgumentException: ExternalGraphic location URL cannot be null
at org.geotools.styling.ExternalGraphicImpl.setLocation(ExternalGraphicImpl.java:131)
at org.geotools.styling.StyleFactoryImpl.createExternalGraphic(StyleFactoryImpl.java:482)
at org.geotools.styling.visitor.DuplicatingStyleVisitor.visit(DuplicatingStyleVisitor.java:887)
at org.geotools.styling.ExternalGraphicImpl.accept(ExternalGraphicImpl.java:142)
at org.geotools.styling.visitor.DuplicatingStyleVisitor.copy(DuplicatingStyleVisitor.java:480)
at org.geotools.styling.visitor.DuplicatingStyleVisitor.copy(DuplicatingStyleVisitor.java:853)
at org.geotools.styling.visitor.DuplicatingStyleVisitor.visit(DuplicatingStyleVisitor.java:802)
at org.geotools.styling.GraphicImpl.accept(GraphicImpl.java:349)
at org.geotools.styling.visitor.DuplicatingStyleVisitor.copy(DuplicatingStyleVisitor.java:402)
at org.geotools.styling.visitor.DuplicatingStyleVisitor.visit(DuplicatingStyleVisitor.java:703)
at org.geotools.styling.visitor.UomRescaleStyleVisitor.visit(UomRescaleStyleVisitor.java:156)
at org.geotools.styling.PointSymbolizerImpl.accept(PointSymbolizerImpl.java:93)
at org.geotools.styling.visitor.DuplicatingStyleVisitor.copy(DuplicatingStyleVisitor.java:511)
at org.geotools.styling.visitor.DuplicatingStyleVisitor.visit(DuplicatingStyleVisitor.java:281)
at org.geotools.renderer.lite.StreamingRenderer.rescaleFeatureTypeStyle(StreamingRenderer.java:2289)
at org.geotools.renderer.lite.StreamingRenderer.applyUnitRescale(StreamingRenderer.java:2150)
at org.geotools.renderer.lite.StreamingRenderer.createLiteFeatureTypeStyles(StreamingRenderer.java:1788)
at org.geotools.renderer.lite.StreamingRenderer.processStylers(StreamingRenderer.java:1920)
at org.geotools.renderer.lite.StreamingRenderer.paint(StreamingRenderer.java:835)
at org.geotools.swing.RenderingTask.call(RenderingTask.java:106)
at org.geotools.swing.RenderingTask.call(RenderingTask.java:41)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:748)

The only URI / URL that I handle is not null since there is no URI syntax error message. So I've got some difficulties to interpret the error message and therefore to correct the mistake in my source code.

1 Answer 1

1

Something is up with the style you are creating and rather than step through your code to find out exactly where it goes wrong, I rewrote it using the much simpler StyleBuilder class which is designed for this sort of job. I also threw in an writeSLD method to help with debugging.

public static Layer createLayer(DataStore dataStore) throws TransformerException {
        // category == 17 <==> tower
        StyleBuilder builder = new StyleBuilder(FF);
        // simple circle backup plan
        Stroke stroke = builder.createStroke(Color.black);// SF.stroke(FF.literal("#000000"),
                                                            // null, null, null,
                                                            // null, null,
                                                            // null);
        Fill fill = builder.createFill(Color.BLUE);// SF.fill(null,
                                                    // FF.literal(Color.BLUE),
                                                    // FF.literal(1.0f));
        Expression size = FF.literal(POINT_SIZE);

        // define a point symbolizer for towers
        ExternalGraphic extGraphic = builder.createExternalGraphic(TOWER_ICON_PATH, "image/svg");

        Graphic graphic = builder.createGraphic(extGraphic, builder.createMark("circle", fill, stroke), null);
        graphic.setSize(size);

        PointSymbolizer pointSymbolizer = builder.createPointSymbolizer(graphic);

        PropertyIsEqualTo piet = FF.equals(FF.property("category"), FF.literal(17));
        Rule towerRule = builder.createRule(pointSymbolizer);
        towerRule.setName("rule for tower landmarks");
        towerRule.setFilter(piet);
        FeatureTypeStyle fts = builder.createFeatureTypeStyle("Feature", towerRule);

        Style style = builder.createStyle();
        style.featureTypeStyles().add(fts);
        writeSLD(style);

        SimpleFeatureSource featureSource = null;
        try {
            featureSource = dataStore.getFeatureSource(LANDMARK_FEATURE_NAME);
        } catch (IOException ex) {
            System.out.flush();
            System.err.println("Unable to find the feature called " + LANDMARK_FEATURE_NAME + " in database");
            System.exit(1);
        }

        Layer layer = new FeatureLayer(featureSource, style);

        return layer;
    }

    static void writeSLD(Style s) throws TransformerException {
        StyledLayerDescriptor sld = SF.createStyledLayerDescriptor();
        UserLayer layer = SF.createUserLayer();
        layer.setLayerFeatureConstraints(new FeatureTypeConstraint[] { null });
        sld.addStyledLayer(layer);
        layer.addUserStyle(s);
        SLDTransformer styleTransform = new SLDTransformer();
        styleTransform.setIndentation(2);
        String xml = styleTransform.transform(sld);
        System.out.println(xml);
    }
5
  • I tried your code. It raises the same error message and before printing SLD XML file it raises a warning message:Warning: Could not get charToByteConverterClass! Commented Jul 17, 2018 at 7:48
  • I would try with an absolute path to the icon then.
    – Ian Turton
    Commented Jul 17, 2018 at 8:01
  • Same error message with an absolute file path. So I tried to load the SVG file as a resource included in my jar file. Result: he finds the resource and loads it... but the same error message is raised. Commented Jul 17, 2018 at 8:16
  • OK, please expand your code to a mvp that generates the error for me. Also include links to the svg file.
    – Ian Turton
    Commented Jul 17, 2018 at 8:18
  • You can retrieve the source files in Google Drive: drive.google.com/drive/folders/… Main file is Odyssey.java. The file generating the error message is LandmarkLayer.java. Commented Jul 17, 2018 at 8:41

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.