Skip to content

FLX-1002

Exported service method 'com.example.PriceQuery.lastPrice' returns java.lang.String, which cannot be generated

Severity ERROR
Category ANNOTATION
Element NODE

The rule

An @ExportService method must return void, or boolean to control propagation.

Why the compiler says this

The generated processor implements the exported interface, and Fluxtion renders every exported method as a void dispatch that calls the node and returns. There is nowhere for a value to come back through, so a method declaring one produces an override that does not match the interface and the generated source fails to compile. Reported here, before generation, so the failure names your interface rather than a line inside generated code. boolean is exempt: it compiles and controls whether the call marks the node dirty.

How to fix it

Change com.example.PriceQuery.lastPrice to return void — an exported method is a command, and its value is discarded either way. If it is a QUERY, do not export it: read the node with flow.getNodeById("priceNode") and call the method on the node directly. If the return value was controlling propagation, declare it boolean.

Example

Both examples are compiled and put through a real Fluxtion.compile on every build, so the first is guaranteed to produce this diagnostic and the second to build cleanly. Note that the failing example is valid Java — javac is happy, and Fluxtion refuses it for its own reasons.

The code that causes it

package com.telamin.fluxtion.builder.diagnostic.examples;

import com.telamin.fluxtion.builder.generation.config.EventProcessorConfig;
import com.telamin.fluxtion.runtime.annotations.ExportService;

/** FLX-1002 — an exported method that returns a value. */
public class Flx1002Failing {

    public interface PriceQuery {
        // A QUERY. The generated processor implements this interface, and Fluxtion renders every
        // exported method as a void dispatch — there is nowhere for a value to come back through.
        String lastPrice();
    }

    public static class PriceNode implements @ExportService PriceQuery {
        private String price = "unset";

        @Override
        public String lastPrice() {
            return price;
        }
    }

    public static void graph(EventProcessorConfig config) {
        config.addNode(new PriceNode(), "priceNode");
    }
}

The code that fixes it

package com.telamin.fluxtion.builder.diagnostic.examples;

import com.telamin.fluxtion.builder.generation.config.EventProcessorConfig;
import com.telamin.fluxtion.runtime.annotations.ExportService;

/** FLX-1002 fixed — commands are exported; the query reads the node directly. */
public class Flx1002Fixed {

    public interface PriceCommands {
        // void: a command surface, which is what @ExportService is for.
        void reset();

        // boolean is also accepted: it controls whether the call marks the node dirty.
        boolean applyTick(int tick);
    }

    public static class PriceNode implements @ExportService PriceCommands {
        private String price = "unset";

        @Override
        public void reset() {
            price = "unset";
        }

        @Override
        public boolean applyTick(int tick) {
            price = String.valueOf(tick);
            return true;
        }

        // Not exported. To READ the node, look it up:
        //     PriceNode node = flow.getNodeById("priceNode");
        //     String price = node.lastPrice();
        public String lastPrice() {
            return price;
        }
    }

    public static void graph(EventProcessorConfig config) {
        config.addNode(new PriceNode(), "priceNode");
    }
}

Which builds raise it

Source-generating (AOT) builds only, and raised BEFORE generation so the failure names your interface instead of a line inside generated code.

Reading it programmatically

This diagnostic is also written to the machine-readable report — the opt-in sidecar (-Dfluxtion.diagnostics.sidecar=true), or FluxtionDiagnostics.capture(...) for a caller that wants the objects:

{
  "code": "FLX-1002",
  "severity": "ERROR",
  "category": "ANNOTATION",
  "element": { "kind": "NODE",  }
}

Select findings by severity, never by position: a failing build's report also contains any warnings it found, and diagnostics[0] is not the cause of the failure.


This page is generated from the compiler itself, so the wording above is exactly what a build emits. Do not edit it by hand — it is overwritten whenever the diagnostics are regenerated.