private void exportDocFactory(File outputDir, String packageName) {
        File dirForSources = new File(outputDir, packageName.replaceAll("\\.", "/"));
        dirForSources.mkdirs();
        File target = new File(dirForSources, "ConcreteDocumentFactory.java");
        if (target.lastModified() > newestModifiedTime) {
            getLog().debug("No changes, not updating "+target);
            return;
        }
        try (Writer out = new FileWriter(target)) {
                out.write("package "+packageName+";\n\n" +
                    "/**\n" +
                    " *  Registry of generated concrete document, struct and annotation types.\n" +
                    " *\n" +
                    " *  Generated by vespa-documentgen-plugin, do not edit.\n" +
                    " *  Date: "+new Date()+"\n" +
                    " */\n");
            out.write("@com.yahoo.document.Generated\n");
            out.write("public class ConcreteDocumentFactory extends com.yahoo.docproc.AbstractConcreteDocumentFactory {\n");
            out.write(ind()+"private static java.util.Map<java.lang.String, java.lang.Class<? extends com.yahoo.document.Document>> dTypes = new java.util.HashMap<java.lang.String, java.lang.Class<? extends com.yahoo.document.Document>>();\n");
            out.write(ind()+"private static java.util.Map<java.lang.String, com.yahoo.document.DocumentType> docTypes = new java.util.HashMap<>();\n");
            out.write(ind()+"private static java.util.Map<java.lang.String, java.lang.Class<? extends com.yahoo.document.datatypes.Struct>> sTypes = new java.util.HashMap<java.lang.String, java.lang.Class<? extends com.yahoo.document.datatypes.Struct>>();\n");
            out.write(ind()+"private static java.util.Map<java.lang.String, java.lang.Class<? extends com.yahoo.document.annotation.Annotation>> aTypes = new java.util.HashMap<java.lang.String, java.lang.Class<? extends com.yahoo.document.annotation.Annotation>>();\n");
            out.write(ind()+"static {\n");
            for (Map.Entry<String, String> e : docTypes.entrySet()) {
                String docTypeName = e.getKey();
                String fullClassName = e.getValue();
                out.write(ind(2)+"dTypes.put(\""+docTypeName+"\","+fullClassName+".class);\n");
            }
            for (Map.Entry<String, String> e : docTypes.entrySet()) {
                String docTypeName = e.getKey();
                String fullClassName = e.getValue();
                out.write(ind(2)+"docTypes.put(\""+docTypeName+"\","+fullClassName+".type);\n");
            }
            for (Map.Entry<String, String> e : structTypes.entrySet()) {
                String structTypeName = e.getKey();
                String fullClassName = e.getValue();
                out.write(ind(2)+"sTypes.put(\""+structTypeName+"\","+fullClassName+".class);\n");
            }
            for (Map.Entry<String, String> e : annotationTypes.entrySet()) {
                String annotationTypeName = e.getKey();
                String fullClassName = e.getValue();
                out.write(ind(2)+"aTypes.put(\""+annotationTypeName+"\","+fullClassName+".class);\n");
            }
            for (Annotation a : provided) {
                out.write(ind(2)+"aTypes.put(\""+a.type+"\","+a.clazz+".class);\n");
            }
            out.write(ind()+"}\n\n");

            out.write(
                    ind()+"public static final java.util.Map<java.lang.String, java.lang.Class<? extends com.yahoo.document.Document>> documentTypes = java.util.Collections.unmodifiableMap(dTypes);\n" +
                    ind()+"public static final java.util.Map<java.lang.String, com.yahoo.document.DocumentType> documentTypeObjects = java.util.Collections.unmodifiableMap(docTypes);\n" +
                    ind()+"public static final java.util.Map<java.lang.String, java.lang.Class<? extends com.yahoo.document.datatypes.Struct>> structTypes = java.util.Collections.unmodifiableMap(sTypes);\n" +
                    ind()+"public static final java.util.Map<java.lang.String, java.lang.Class<? extends com.yahoo.document.annotation.Annotation>> annotationTypes = java.util.Collections.unmodifiableMap(aTypes);\n\n");
            out.write(
                    ind()+"@Override public java.util.Map<java.lang.String, java.lang.Class<? extends com.yahoo.document.Document>> documentTypes() { return ConcreteDocumentFactory.documentTypes; }\n" +
                    ind()+"@Override public java.util.Map<java.lang.String, java.lang.Class<? extends com.yahoo.document.datatypes.Struct>> structTypes() { return ConcreteDocumentFactory.structTypes; }\n" +
                    ind()+"@Override public java.util.Map<java.lang.String, java.lang.Class<? extends com.yahoo.document.annotation.Annotation>> annotationTypes() { return ConcreteDocumentFactory.annotationTypes; }\n\n");

            out.write(
                    ind()+"/**\n" +
                    ind()+" * Returns a new Document which will be of the correct concrete type and a copy of the given StructFieldValue.\n" +
                    ind()+" */\n" +
                    ind()+"@Override public com.yahoo.document.Document getDocumentCopy(java.lang.String type, com.yahoo.document.datatypes.StructuredFieldValue src, com.yahoo.document.DocumentId id) {\n");
                    for (Map.Entry<String, String> e : docTypes.entrySet()) {
                        out.write(ind(2)+"if (\""+e.getKey()+"\".equals(type)) return new "+e.getValue()+"(src, id);\n");
                    }
                    out.write(ind(2)+"throw new java.lang.IllegalArgumentException(\"No such concrete document type: \"+type);\n");
                    out.write(ind()+"}\n\n");

            // delete, bad to use reflection?
            out.write(
                    ind()+"/**\n" +
                    ind()+" * Returns a new Document which will be of the correct concrete type.\n" +
                    ind()+" */\n" +
                    ind()+"public static com.yahoo.document.Document getDocument(java.lang.String type, com.yahoo.document.DocumentId id) {\n" +
                    ind(2)+"if (!ConcreteDocumentFactory.documentTypes.containsKey(type)) throw new java.lang.IllegalArgumentException(\"No such concrete document type: \"+type);\n" +
                    ind(2)+"try {\n" +
                    ind(3)+"return ConcreteDocumentFactory.documentTypes.get(type).getConstructor(com.yahoo.document.DocumentId.class).newInstance(id);\n" +
                    ind(2)+"} catch (java.lang.Exception ex) { throw new java.lang.RuntimeException(ex); }\n" +
                    ind()+"}\n\n");

            // delete, bad to use reflection?
            out.write(
                    ind()+"/**\n" +
                    ind()+" * Returns a new Struct which will be of the correct concrete type.\n" +
                    ind()+" */\n" +
                    ind()+"public static com.yahoo.document.datatypes.Struct getStruct(java.lang.String type) {\n" +
                    ind(2)+"if (!ConcreteDocumentFactory.structTypes.containsKey(type)) throw new java.lang.IllegalArgumentException(\"No such concrete struct type: \"+type);\n" +
                    ind(2)+"try {\n" +
                    ind(3)+"return ConcreteDocumentFactory.structTypes.get(type).getConstructor().newInstance();\n" +
                    ind(2)+"} catch (java.lang.Exception ex) { throw new java.lang.RuntimeException(ex); }\n" +
                    ind()+"}\n\n");

            // delete, bad to use reflection?
            out.write(
                    ind()+"/**\n" +
                    ind()+" * Returns a new Annotation which will be of the correct concrete type.\n" +
                    ind()+" */\n" +
                    ind()+"public static com.yahoo.document.annotation.Annotation getAnnotation(java.lang.String type) {\n" +
                    ind(2)+"if (!ConcreteDocumentFactory.annotationTypes.containsKey(type)) throw new java.lang.IllegalArgumentException(\"No such concrete annotation type: \"+type);\n" +
                    ind(2)+"try {\n" +
                    ind(3)+"return ConcreteDocumentFactory.annotationTypes.get(type).getConstructor().newInstance();\n" +
                    ind(2)+"} catch (java.lang.Exception ex) { throw new java.lang.RuntimeException(ex); }\n" +
                    ind()+"}\n\n");

            out.write("}\n");
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
The class for this type if provided, otherwise null
vespa-documentgen-plugin/src/main/java/com/yahoo/vespa/DocumentGenMojo.java