javams-wordapache-poiword-template

create new document from template


I want to open a new document from a MS-Word template from my Java-App, but only manage to edit the template itself.

Here is my situation: Inside my Jar file is a word template, that gets copied to a user-specified location, so he/she can edit it. Afterwards, the application can open this edited template, insert data into it and open it in word. This all works fine (using Apache-POI), but the last step is not entirely what I want.

Normally, when double-clicking a word-template, Word would open a NEW document (titled Document1) that is not saved anywhere yet. In my case, Word opens the word-template for editing (titled blablaMyTemplate), meaning the already saved template from which documents should be created. How do I manage to open a newly created document from the template using Java?

This is my code (try/catch and stream closing omitted):

    File bbb = new File(new File(getClass().getProtectionDomain().getCodeSource().getLocation().toURI().getPath()).getParentFile().getParentFile().getAbsolutePath() + "/blablaMyTemplate.dotx");
    if (!bbb.exists()) { //copy file to outside of jar for user editing
        Files.copy(Buchungsbegleitblatt.class.getResourceAsStream("bbb.dotx"), bbb.toPath(), StandardCopyOption.REPLACE_EXISTING);
    }
    File tmp = File.createTempFile("bbb", ".dotx"); //create tmp file to insert data
    InputStream in = new FileInputStream(bbb);
    OutputStream out = new FileOutputStream(tmp);
    XWPFDocument document = new XWPFDocument(in);
    //here, some data is filled into the document using Apache-POI (omitted, because it works fine)
    document.write(out);
    if (Desktop.isDesktopSupported()) {
        Desktop.getDesktop().open(tmp); //this opens the template for editing, it does not create a new doc from template
    }

The issue lies within the last line, but I have no idea what else I could call here.

To make it a little clearer, here is an image of the context menu I get on the template file and what is supposed to happen:

context menu on template


Solution

  • You have exactly described the problem already. Desktop.open will exactly do what it says. It will perform the open event for the called application which is assigned to the file type.

    What you need is to perform the new event. This can be achieved in Word using startup command-line switches to start Word.

    In the linked knowledge base entry you can find:

    ...

    /ttemplate_name Starts Word with a new document based on a template other than the Normal template.

    ...

    To do so with Java either Runtime.getRuntime().exec or ProcessBuilder can be used. With both I would recommend first to start the command interpreter CMD as a shell and use the start command from this to start the application. So we avoid the need to know the exact path to the application.

    Examples:

    import java.io.*;
    
    class RuntimeExec {
      public static void main(String[] args) {
          try {
            // Execute a command as a single line
            File f = new File("C:/Users/axel/Documents/The Template.dotx");
            System.out.println(f.getAbsolutePath());
            String cmd = "cmd /C start winword.exe /t\"" + f.getAbsolutePath() + "\"";
            Process child = Runtime.getRuntime().exec(cmd);
    
          } catch (IOException e) {
            e.printStackTrace();
          }
    
      }
    }
    
    class UseProcessBuilder {
      public static void main(String[] args) {
          try {
            //use ProcessBuilder to have more control
            File f = new File("C:/Users/axel/Documents/The Template.dotx");
            System.out.println(f.getAbsolutePath());
            String application = "winword.exe";
            String switchNewFromTemplate = "/t";
            String file = f.getAbsolutePath(); 
            ProcessBuilder pb = new ProcessBuilder("cmd", "/C", "start", application, switchNewFromTemplate+file);
            Process process = pb.start();
    
          } catch (IOException e) {
            e.printStackTrace();
          }
      }
    }
    

    There is one possibility to not explicitly start the winword application. The start command has the feature to perform the default action according to the file extension with the given file if we give a empty string "" as the application name:

    start "" "The name of the file.ext"

    Example:

    start "" "The name of the file.dotx"

    This will perform the default action new in winword application which is related to the dotx extension in registry database.

    So:

    class RuntimeExec {
      public static void main(String[] args) {
          try {
            // Execute a command as a single line
            File f = new File("C:/Users/Axel Richter/Documents/The Template.dotx");
            System.out.println(f.getAbsolutePath());
            String cmd = "cmd /C start \"\" \"" + f.getAbsolutePath() + "\"";
            Process child = Runtime.getRuntime().exec(cmd);
    
            InputStream in = child.getErrorStream();
            int c;
            while ((c = in.read()) != -1) {
                System.out.print((char)c);
            }
            in.close();
    
          } catch (IOException e) {
            e.printStackTrace();
          }
    
      }
    }
    
    class UseProcessBuilder {
      public static void main(String[] args) {
          try {
            //use ProcessBuilder to have more control
            File f = new File("C:/Users/Axel Richter/Documents/The Template.dotx");
            System.out.println(f.getAbsolutePath());
            String file = f.getAbsolutePath(); 
            ProcessBuilder pb = new ProcessBuilder("cmd", "/C", "start", "\"\"", file);
            Process process = pb.start();
    
            InputStream in = process.getErrorStream();
            int c;
            while ((c = in.read()) != -1) {
                System.out.print((char)c);
            }
            in.close();
    
          } catch (IOException e) {
            e.printStackTrace();
          }
      }
    }