I implemented a Formatter2, which works nicely in the IDE when hitting
Strg-Shift-F. However, when I programmatically save a resource, the
serializer of the Xtext Resource is always the OneSpaceFormatter and not
my formatter 2.

I have the same issue as the OP, basically that when programmatically trying to format using just the runtime project, not the UI, then the formatter that is used is always OneWhitespaceFormatter, even when an alternate Formatter2 is available.

More specifically, I have a single Xtext runtime project with Maven structure. The workflow is configured to generate Formatter2, and it does. I've implemented my Formatter2 formatter, and have implemented a unit test (in the same project under src/test/java) to test it. The test runs fine, but my Formatter2 implementation is never invoked. Using the debugger, I note that when I "format" DefaultNodeModelFormatter.format() is called, which then uses a dependency injected IFormatter (i.e., a OneWhitespaceFormatter instance). An instance of my Formatter2 implementation is created by the injection framework and available.

I dug around in some other Xtext projects that I have that do have UI's, some with Formatter2 implementations, and some without. The ones that do have this:

in their Abstract<MYDSL>UiModule, which would explain why it works in the UI.

I suspect that Formatter2 "handling" in just the runtime project is not implemented yet. One way forward would be for me to override bindINodeModelFormatter() in my DSL's RuntimeModule and return a custom implementation of INodeModelFromatter to support Formatter2.

Am I missing something?
Would this create problems if/when I do develop a UI?
Has this already been addressed in a new version?

..quick response...As a quick test, I dropped the two generated lines into my Abstract*RuntimeModule and added some breakpoints. They're both called, but it's still defaulting to the old OneSpace Formatter.

Maybe there's something else that's generated?

I switched to using XtextGeneratorLanguage to get as much control as I could on the generation process. The parser is being embedded in something else and I don't (currently) need all the extra stuff for a full-scale editor or IDE integration.

Daniel, this looks like the code snippet in the first edition of the Xtext book, and it is based on the old formatter, you can't use that with the new formatter. The second edition of the book deals with the new formatter, which is also much easier to test, as Christian showed.

From the documentation, it would seem that "fragment = formatting.Formatter2Fragment2()" would do the trick to produce Formatter2 support using XtextGeneratorLanguage in the runtime project, but I haven't found that to be the case. So, it would seem like there's either a bug in the code, or a bug in the documentation.

The guice bindings for the runtime project are produced in org.eclipse.xtext.generator.formatting2.Formatter2Fragment.getGuiceBindingsRt(), but it's never called during the XtextGeneratorLanguage workflow.

Ok, I'm making progress. The correct guice bindings are now being generated in the runtime project using the XtextGeneratorLanguage. I was convinced that they were not being generated, but now that is working. Who knows? Probably my mistake. Using the FormatterTester also now invokes my Formatter2 code.