javam2doc

Using M2Doc programmatically : Error in the generated .docx document


I'm trying to use M2Doc programmatically, I managed to generate my .docx file without getting errors in the validation part but I'm getting the following Error in the generated document:

{m:self.Name} Couldn't find the 'aqlFeatureAccess(org.eclipse.emf.common.util.URI.Hierarchical,java.lang.String)' service

The "self.Name" part is what I wrote in my template.

I think I'm lacking some kind of reference to a service but I don't know how to fix it.

The self variable is a reference to a model based on a meta-model I created. But I'm not sure I imported it correctly in my code.

I based my code on the code I found on the M2Doc website + some code I found on their GitHub, especially concerning how to add a service in the queryEnvironment.

I searched in the source code of acceleo and M2Doc to see which services they add but it seems that they already import all the services I'm using.

As I said, the validation part is going well and doesn't generate a validation file.

    public static void parseDocument(String templateName) throws Exception{
        final URI templateURI = URI.createFileURI("Template/"+templateName+"."+M2DocUtils.DOCX_EXTENSION_FILE);
        final IQueryEnvironment queryEnvironment = 
                org.eclipse.acceleo.query.runtime.Query.newEnvironmentWithDefaultServices(null); 
        final Map<String, String> options = new HashMap<>(); // can be empty
        M2DocUtils.prepareEnvironmentServices(queryEnvironment, templateURI, options); // delegate to IServicesConfigurator

        prepareEnvironmentServicesCustom(queryEnvironment, options);

        final IClassProvider classProvider = new ClassProvider(ClassLoader.getSystemClassLoader()); // use M2DocPlugin.getClassProvider() when running inside Eclipse
        try (DocumentTemplate template = M2DocUtils.parse(templateURI, queryEnvironment, classProvider)) {
            ValidationMessageLevel validationLevel = validateDocument(template, queryEnvironment, templateName);
            if(validationLevel == ValidationMessageLevel.OK){
                generateDocument(template, queryEnvironment, templateName, "Model/ComplexKaosModel.kaos");
            }
        }
    }
    public static void prepareEnvironmentServicesCustom(IQueryEnvironment queryEnvironment, Map<String, String> options){

        Set<IService> services = ServiceUtils.getServices(queryEnvironment, FilterService.class);
        ServiceUtils.registerServices(queryEnvironment, services);

        M2DocUtils.getConfigurators().forEach((configurator) -> {
            ServiceUtils.registerServices(queryEnvironment, configurator.getServices(queryEnvironment, options));
        });
    }
    public static void generateDocument(DocumentTemplate template, IQueryEnvironment queryEnvironment,
            String templateName, String modelPath)throws Exception{

        final Map<String, Object> variable = new HashMap<>();
        variable.put("self", URI.createFileURI(modelPath));
        final Monitor monitor = new BasicMonitor.Printing(System.out);
        final URI outputURI = URI.createFileURI("Generated/"+templateName+".generated."+M2DocUtils.DOCX_EXTENSION_FILE);
        M2DocUtils.generate(template, queryEnvironment, variable, outputURI, monitor);
    }

Solution

  • The variable "self" contains an URI:

    variable.put("self", URI.createFileURI(modelPath));
    

    You have to load your model and set the value of self to an element from your model using something like:

    final ResourceSet rs = new ResourceSetImpl();
    final Resource r = rs.getResource(uri, true);
    final EObject value = r.getContents()...;
    variable.put("self", value);
    

    You can get more details on resource loading in the EMF documentation.