Repository: redpen-cc/redpen
Pull request #548 (2016-02-11 14:53:09)

Implement ConfigurationExporter in redpen-core
Please review commits one by one to make understanding easier.



Patch:
diff --git a/redpen-core/src/main/java/cc/redpen/ConfigurationLoader.java b/redpen-core/src/main/java/cc/redpen/ConfigurationLoader.java
index b02d67b6..775e5f7c 100644
--- a/redpen-core/src/main/java/cc/redpen/ConfigurationLoader.java
+++ b/redpen-core/src/main/java/cc/redpen/ConfigurationLoader.java
@@ -1,273 +1,8 @@
-/**
- * redpen: a text inspection tool
- * Copyright (c) 2014-2015 Recruit Technologies Co., Ltd. and contributors
- * (see CONTRIBUTORS.md)
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
 package cc.redpen;
 
-import cc.redpen.config.Configuration;
-import cc.redpen.config.Symbol;
-import cc.redpen.config.SymbolType;
-import cc.redpen.config.ValidatorConfiguration;
-import cc.redpen.util.SAXErrorHandler;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-import org.w3c.dom.Node;
-import org.w3c.dom.NodeList;
-import org.xml.sax.SAXException;
-
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.parsers.ParserConfigurationException;
-import java.io.*;
-import java.nio.charset.StandardCharsets;
-
-import static cc.redpen.config.Configuration.ConfigurationBuilder;
-
 /**
- * Load the central configuration of {@link cc.redpen.RedPen}.
+ * @deprecated use {@link cc.redpen.config.ConfigurationLoader} instead
  */
-public final class ConfigurationLoader {
-    private static final Logger LOG =
-            LoggerFactory.getLogger(ConfigurationLoader.class);
-    private ConfigurationBuilder configBuilder = new ConfigurationBuilder();
-
-    private static Symbol createSymbol(Element element) throws RedPenException {
-        if (!element.hasAttribute("name") || !element.hasAttribute("value")) {
-            throw new IllegalStateException("Found element does not have name and value attribute...");
-        }
-        String value = element.getAttribute("value");
-        if (value.length() != 1) {
-            throw new RedPenException("value should be one character, specified: " + value);
-        }
-        char charValue = value.charAt(0);
-        return new Symbol(
-                SymbolType.valueOf(element.getAttribute("name")),
-                charValue,
-                element.getAttribute("invalid-chars"),
-                Boolean.parseBoolean(element.getAttribute("before-space")),
-                Boolean.parseBoolean(element.getAttribute("after-space")));
-    }
-
-
-    /**
-     * parse the input stream. stream will be closed.
-     *
-     * @param input stream
-     * @return document object
-     * @throws RedPenException when failed to parse
-     */
-    private static Document toDocument(InputStream input) throws RedPenException {
-        DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
-        try (BufferedInputStream bis = new BufferedInputStream(input)) {
-            DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
-            dBuilder.setErrorHandler(new SAXErrorHandler());
-            return dBuilder.parse(bis);
-        } catch (SAXException | IOException | ParserConfigurationException e) {
-            throw new RedPenException(e);
-        }
-    }
-
-    /**
-     * load {@link cc.redpen.RedPen} settings.
-     *
-     * @param configFile input configuration file
-     * @return Validator configuration resources
-     * @throws cc.redpen.RedPenException when failed to load configuration from specified configuration file
-     */
-    public Configuration load(File configFile) throws RedPenException {
-        LOG.info("Loading config from specified config file: \"{}\"", configFile.getAbsolutePath());
-        try (InputStream fis = new FileInputStream(configFile)) {
-            return this.load(fis);
-        } catch (IOException e) {
-            throw new RedPenException(e);
-        }
-    }
-
-    /**
-     * load {@link cc.redpen.RedPen} settings.
-     *
-     * @param resourcePath input configuration path
-     * @return Validator configuration resources
-     * @throws cc.redpen.RedPenException when failed to load configuration from specified resource
-     */
-    public Configuration loadFromResource(String resourcePath) throws RedPenException {
-        InputStream inputConfigStream = Configuration.class.getResourceAsStream(resourcePath);
-        return load(inputConfigStream);
-    }
-
-    /**
-     * load {@link cc.redpen.RedPen} settings.
-     *
-     * @param configString configuration as String
-     * @return Validator configuration resources
-     * @throws cc.redpen.RedPenException when failed to load Configuration from specified string
-     */
-    public Configuration loadFromString(String configString) throws RedPenException {
-        return load(new ByteArrayInputStream(configString.getBytes(StandardCharsets.UTF_8)));
-    }
-
-    /**
-     * load {@link cc.redpen.RedPen} configuration.
-     * Provided stream will be closed.
-     *
-     * @param stream input configuration settings
-     * @return Configuration loaded from input stream
-     * @throws cc.redpen.RedPenException when failed to load configuration from specified stream
-     */
-    public Configuration load(InputStream stream) throws RedPenException {
-        Document doc = toDocument(stream);
-
-        configBuilder = new ConfigurationBuilder();
-        Element rootElement = getRootNode(doc, "redpen-conf");
-
-        String language = rootElement.getAttribute("lang");
-        if (!language.isEmpty()) {
-            LOG.info("Language is set to \"{}\"", language);
-        } else {
-            LOG.warn("No language configuration...");
-            LOG.info("Set language to en");
-            language = "en";
-        }
-
-        String variant = rootElement.getAttribute("variant");
-        if (variant.isEmpty()) {
-            variant = rootElement.getAttribute("type");
-            if (!variant.isEmpty()) LOG.info("Deprecated: use \"variant\" attribute instead of \"type\"");
-        }
-
-        if (variant.isEmpty()) {
-            LOG.warn("No variant configuration...");
-        } else {
-            LOG.info("Variant is set to \"{}\"", variant);
-        }
-
-        // extract validator configurations
-        NodeList validatorConfigElementList =
-                getSpecifiedNodeList(rootElement, "validators");
-        if (validatorConfigElementList == null) {
-            LOG.error("There is no validator-list block");
-            return null;
-        }
-        NodeList validatorElementList =
-                validatorConfigElementList.item(0).getChildNodes();
-        if (validatorElementList == null) {
-            LOG.error("There is no validator block");
-            return null;
-        }
-        extractValidatorConfigurations(validatorElementList);
-
-        // extract symbol configurations
-        NodeList symbolTableConfigElementList =
-                getSpecifiedNodeList(rootElement, "symbols");
-        configBuilder.setLanguage(language);
-        if (!variant.isEmpty()) configBuilder.setVariant(variant);
-
-        if (symbolTableConfigElementList != null) {
-            extractSymbolConfig(symbolTableConfigElementList, language);
-        }
-        return configBuilder.build();
-    }
-
-    private void extractValidatorConfigurations(NodeList validatorElementList) {
-        ValidatorConfiguration currentConfiguration;
-        for (int i = 0; i < validatorElementList.getLength(); i++) {
-            Node nNode = validatorElementList.item(i);
-            if (nNode.getNodeType() != Node.ELEMENT_NODE) {
-                continue;
-            }
-            Element element = (Element) nNode;
-            if (element.getNodeName().equals("validator")) {
-                currentConfiguration =
-                        new ValidatorConfiguration(element.getAttribute("name"));
-                configBuilder.addValidatorConfig(currentConfiguration);
-                NodeList propertyElementList = nNode.getChildNodes();
-                extractProperties(currentConfiguration, propertyElementList);
-            } else {
-                LOG.warn("Invalid block: \"" + element.getNodeName() + "\"");
-                LOG.warn("Skip this block ...");
-            }
-        }
-    }
-
-    private void extractProperties(ValidatorConfiguration currentConfiguration,
-                                   NodeList propertyElementList) {
-        for (int j = 0; j < propertyElementList.getLength(); j++) {
-            Node pNode = propertyElementList.item(j);
-            if (pNode.getNodeType() != Node.ELEMENT_NODE) {
-                continue;
-            }
-            Element propertyElement = (Element) pNode;
-            if (propertyElement.getNodeName().equals("property")
-                    && currentConfiguration != null) {
-                currentConfiguration.addAttribute(
-                        propertyElement.getAttribute("name"),
-                        propertyElement.getAttribute("value"));
-            }
-        }
-    }
-
-    private void extractSymbolConfig(NodeList symbolTableConfigElementList, String language) throws RedPenException {
-        configBuilder.setLanguage(language);
-
-        NodeList symbolTableElementList =
-                getSpecifiedNodeList((Element)
-                        symbolTableConfigElementList.item(0), "symbol");
-        if (symbolTableElementList == null) {
-            LOG.warn("there is no character block");
-            return;
-        }
-        for (int temp = 0; temp < symbolTableElementList.getLength(); temp++) {
-            Node nNode = symbolTableElementList.item(temp);
-            if (nNode.getNodeType() == Node.ELEMENT_NODE) {
-                Element element = (Element) nNode;
-                Symbol currentSymbol = createSymbol(element);
-                configBuilder.addSymbol(currentSymbol);
-            }
-        }
-    }
-
-    private NodeList getSpecifiedNodeList(Element rootElement, String elementName) {
-        NodeList elementList =
-                rootElement.getElementsByTagName(elementName);
-        if (elementList.getLength() == 0) {
-            LOG.info("No \"" +
-                    elementName + "\" block found in the configuration");
-            return null;
-        } else if (elementList.getLength() > 1) {
-            LOG.info("More than one \"" + elementName + " \" blocks in the configuration");
-        }
-        return elementList;
-    }
-
-    private Element getRootNode(Document doc, String rootTag) {
-        doc.getDocumentElement().normalize();
-        NodeList rootConfigElementList =
-                doc.getElementsByTagName(rootTag);
-        if (rootConfigElementList.getLength() == 0) {
-            throw new IllegalStateException("No \"" + rootTag
-                    + "\" block found in the configuration");
-        } else if (rootConfigElementList.getLength() > 1) {
-            LOG.warn("More than one \"" +
-                    rootTag + "\" blocks in the configuration");
-        }
-        Node root = rootConfigElementList.item(0);
-        Element rootElement = (Element) root;
-        LOG.info("Succeeded to load configuration file");
-        return rootElement;
-    }
+@Deprecated
+public class ConfigurationLoader extends cc.redpen.config.ConfigurationLoader {
 }
diff --git a/redpen-core/src/main/java/cc/redpen/RedPen.java b/redpen-core/src/main/java/cc/redpen/RedPen.java
index 6329d586..3364f168 100644
--- a/redpen-core/src/main/java/cc/redpen/RedPen.java
+++ b/redpen-core/src/main/java/cc/redpen/RedPen.java
@@ -18,12 +18,9 @@
 package cc.redpen;
 
 import cc.redpen.config.Configuration;
+import cc.redpen.config.ConfigurationLoader;
 import cc.redpen.config.ValidatorConfiguration;
-import cc.redpen.model.Document;
-import cc.redpen.model.ListBlock;
-import cc.redpen.model.ListElement;
-import cc.redpen.model.Paragraph;
-import cc.redpen.model.Section;
+import cc.redpen.model.*;
 import cc.redpen.parser.DocumentParser;
 import cc.redpen.parser.SentenceExtractor;
 import cc.redpen.validator.ValidationError;
@@ -34,11 +31,7 @@ import org.slf4j.LoggerFactory;
 
 import java.io.File;
 import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
 
 /**
  * Validate all input files using appended Validators.
diff --git a/redpen-core/src/main/java/cc/redpen/config/Configuration.java b/redpen-core/src/main/java/cc/redpen/config/Configuration.java
index 92587625..e6af6b43 100644
--- a/redpen-core/src/main/java/cc/redpen/config/Configuration.java
+++ b/redpen-core/src/main/java/cc/redpen/config/Configuration.java
@@ -82,9 +82,9 @@ public class Configuration implements Cloneable {
     }
 
     /**
-     * returns symbol table type targeted by this configuration
+     * returns symbol table variant targeted by this configuration
      *
-     * @return type
+     * @return variant, or empty String if none
      */
     public String getVariant() {
         return getSymbolTable().getVariant();
diff --git a/redpen-core/src/main/java/cc/redpen/config/ConfigurationExporter.java b/redpen-core/src/main/java/cc/redpen/config/ConfigurationExporter.java
new file mode 100644
index 00000000..2bcab416
--- /dev/null
+++ b/redpen-core/src/main/java/cc/redpen/config/ConfigurationExporter.java
@@ -0,0 +1,79 @@
+package cc.redpen.config;
+
+import cc.redpen.util.IndentingXMLStreamWriter;
+
+import javax.xml.stream.XMLOutputFactory;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamWriter;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.util.List;
+import java.util.Map;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+import static java.util.stream.Collectors.toList;
+
+public class ConfigurationExporter {
+
+  public void export(Configuration config, OutputStream out) {
+    try {
+      XMLOutputFactory sf = XMLOutputFactory.newInstance();
+      XMLStreamWriter sax = new IndentingXMLStreamWriter(sf.createXMLStreamWriter(new OutputStreamWriter(out, UTF_8)));
+
+      addRoot(config, sax);
+      addValidators(config.getValidatorConfigs(), sax);
+      addNonDefaultSymbols(config.getSymbolTable(), sax);
+
+      sax.writeEndElement();
+      sax.flush();
+    }
+    catch (XMLStreamException e) {
+      throw new RuntimeException(e);
+    }
+  }
+
+  private void addRoot(Configuration config, XMLStreamWriter sax) throws XMLStreamException {
+    sax.writeStartElement("redpen-conf");
+    sax.writeAttribute("lang", config.getLang());
+    if (!config.getVariant().isEmpty())
+      sax.writeAttribute("variant", config.getVariant());
+  }
+
+  private void addValidators(List<ValidatorConfiguration> validators, XMLStreamWriter sax) throws XMLStreamException {
+    if (validators.isEmpty()) return;
+    sax.writeStartElement("validators");
+
+    for (ValidatorConfiguration v : validators) {
+      if (v.getAttributes().isEmpty()) sax.writeEmptyElement("validator"); else sax.writeStartElement("validator");
+      sax.writeAttribute("name", v.getConfigurationName());
+      for (Map.Entry<String, String> attr : v.getAttributes().entrySet()) {
+        sax.writeEmptyElement("property");
+        sax.writeAttribute("name", attr.getKey());
+        sax.writeAttribute("value", attr.getValue());
+      }
+      if (!v.getAttributes().isEmpty()) sax.writeEndElement();
+    }
+
+    sax.writeEndElement();
+  }
+
+  private void addNonDefaultSymbols(SymbolTable symbolTable, XMLStreamWriter sax) throws XMLStreamException {
+    Map<SymbolType, Symbol> defaults = symbolTable.getDefaultSymbols();
+    List<Symbol> nonDefaultSymbols = symbolTable.getNames().stream()
+      .map(symbolTable::getSymbol)
+      .filter(s -> !s.equals(defaults.get(s.getType()))).collect(toList());
+
+    if (nonDefaultSymbols.isEmpty()) return;
+
+    sax.writeStartElement("symbols");
+    for (Symbol symbol : nonDefaultSymbols) {
+      sax.writeEmptyElement("symbol");
+      sax.writeAttribute("name", symbol.getType().toString());
+      sax.writeAttribute("value", String.valueOf(symbol.getValue()));
+      if (symbol.getInvalidChars().length > 0) sax.writeAttribute("invalid-chars", String.valueOf(symbol.getInvalidChars()));
+      if (symbol.isNeedBeforeSpace()) sax.writeAttribute("before-space", "true");
+      if (symbol.isNeedAfterSpace()) sax.writeAttribute("after-space", "true");
+    }
+    sax.writeEndElement();
+  }
+}
diff --git a/redpen-core/src/main/java/cc/redpen/config/ConfigurationLoader.java b/redpen-core/src/main/java/cc/redpen/config/ConfigurationLoader.java
new file mode 100644
index 00000000..711809fb
--- /dev/null
+++ b/redpen-core/src/main/java/cc/redpen/config/ConfigurationLoader.java
@@ -0,0 +1,265 @@
+/**
+ * redpen: a text inspection tool
+ * Copyright (c) 2014-2015 Recruit Technologies Co., Ltd. and contributors
+ * (see CONTRIBUTORS.md)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package cc.redpen.config;
+
+import cc.redpen.RedPenException;
+import cc.redpen.util.SAXErrorHandler;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.SAXException;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import java.io.*;
+import java.nio.charset.StandardCharsets;
+
+import static cc.redpen.config.Configuration.ConfigurationBuilder;
+
+/**
+ * Load the central configuration of {@link cc.redpen.RedPen}.
+ */
+public class ConfigurationLoader {
+    private static final Logger LOG =
+            LoggerFactory.getLogger(ConfigurationLoader.class);
+    private ConfigurationBuilder configBuilder = new ConfigurationBuilder();
+
+    private static Symbol createSymbol(Element element) throws RedPenException {
+        if (!element.hasAttribute("name") || !element.hasAttribute("value")) {
+            throw new IllegalStateException("Found element does not have name and value attribute...");
+        }
+        String value = element.getAttribute("value");
+        if (value.length() != 1) {
+            throw new RedPenException("value should be one character, specified: " + value);
+        }
+        char charValue = value.charAt(0);
+        return new Symbol(
+                SymbolType.valueOf(element.getAttribute("name")),
+                charValue,
+                element.getAttribute("invalid-chars"),
+                Boolean.parseBoolean(element.getAttribute("before-space")),
+                Boolean.parseBoolean(element.getAttribute("after-space")));
+    }
+
+
+    /**
+     * parse the input stream. stream will be closed.
+     *
+     * @param input stream
+     * @return document object
+     * @throws RedPenException when failed to parse
+     */
+    private static Document toDocument(InputStream input) throws RedPenException {
+        DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
+        try (BufferedInputStream bis = new BufferedInputStream(input)) {
+            DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
+            dBuilder.setErrorHandler(new SAXErrorHandler());
+            return dBuilder.parse(bis);
+        } catch (SAXException | IOException | ParserConfigurationException e) {
+            throw new RedPenException(e);
+        }
+    }
+
+    /**
+     * load {@link cc.redpen.RedPen} settings.
+     *
+     * @param configFile input configuration file
+     * @return Validator configuration resources
+     * @throws cc.redpen.RedPenException when failed to load configuration from specified configuration file
+     */
+    public Configuration load(File configFile) throws RedPenException {
+        LOG.info("Loading config from specified config file: \"{}\"", configFile.getAbsolutePath());
+        try (InputStream fis = new FileInputStream(configFile)) {
+            return this.load(fis);
+        } catch (IOException e) {
+            throw new RedPenException(e);
+        }
+    }
+
+    /**
+     * load {@link cc.redpen.RedPen} settings.
+     *
+     * @param resourcePath input configuration path
+     * @return Validator configuration resources
+     * @throws cc.redpen.RedPenException when failed to load configuration from specified resource
+     */
+    public Configuration loadFromResource(String resourcePath) throws RedPenException {
+        InputStream inputConfigStream = Configuration.class.getResourceAsStream(resourcePath);
+        return load(inputConfigStream);
+    }
+
+    /**
+     * load {@link cc.redpen.RedPen} settings.
+     *
+     * @param configString configuration as String
+     * @return Validator configuration resources
+     * @throws cc.redpen.RedPenException when failed to load Configuration from specified string
+     */
+    public Configuration loadFromString(String configString) throws RedPenException {
+        return load(new ByteArrayInputStream(configString.getBytes(StandardCharsets.UTF_8)));
+    }
+
+    /**
+     * load {@link cc.redpen.RedPen} configuration.
+     * Provided stream will be closed.
+     *
+     * @param stream input configuration settings
+     * @return Configuration loaded from input stream
+     * @throws cc.redpen.RedPenException when failed to load configuration from specified stream
+     */
+    public Configuration load(InputStream stream) throws RedPenException {
+        Document doc = toDocument(stream);
+
+        configBuilder = new ConfigurationBuilder();
+        Element rootElement = getRootNode(doc, "redpen-conf");
+
+        String language = rootElement.getAttribute("lang");
+        if (!language.isEmpty()) {
+            LOG.info("Language is set to \"{}\"", language);
+        } else {
+            LOG.warn("No language configuration...");
+            LOG.info("Set language to en");
+            language = "en";
+        }
+
+        String variant = rootElement.getAttribute("variant");
+        if (variant.isEmpty()) {
+            variant = rootElement.getAttribute("type");
+            if (!variant.isEmpty()) LOG.info("Deprecated: use \"variant\" attribute instead of \"type\"");
+        }
+
+        if (variant.isEmpty()) {
+            LOG.warn("No variant configuration...");
+        } else {
+            LOG.info("Variant is set to \"{}\"", variant);
+        }
+
+        // extract validator configurations
+        NodeList validatorConfigElementList = getSpecifiedNodeList(rootElement, "validators");
+
+        if (validatorConfigElementList == null) {
+            LOG.warn("There is no validators block");
+        } else {
+            NodeList validatorElementList = validatorConfigElementList.item(0).getChildNodes();
+            extractValidatorConfigurations(validatorElementList);
+        }
+
+        // extract symbol configurations
+        NodeList symbolTableConfigElementList =
+                getSpecifiedNodeList(rootElement, "symbols");
+        configBuilder.setLanguage(language);
+        if (!variant.isEmpty()) configBuilder.setVariant(variant);
+
+        if (symbolTableConfigElementList != null) {
+            extractSymbolConfig(symbolTableConfigElementList, language);
+        }
+        return configBuilder.build();
+    }
+
+    private void extractValidatorConfigurations(NodeList validatorElementList) {
+        ValidatorConfiguration currentConfiguration;
+        for (int i = 0; i < validatorElementList.getLength(); i++) {
+            Node nNode = validatorElementList.item(i);
+            if (nNode.getNodeType() != Node.ELEMENT_NODE) {
+                continue;
+            }
+            Element element = (Element) nNode;
+            if (element.getNodeName().equals("validator")) {
+                currentConfiguration =
+                        new ValidatorConfiguration(element.getAttribute("name"));
+                configBuilder.addValidatorConfig(currentConfiguration);
+                NodeList propertyElementList = nNode.getChildNodes();
+                extractProperties(currentConfiguration, propertyElementList);
+            } else {
+                LOG.warn("Invalid block: \"" + element.getNodeName() + "\"");
+                LOG.warn("Skip this block ...");
+            }
+        }
+    }
+
+    private void extractProperties(ValidatorConfiguration currentConfiguration,
+                                   NodeList propertyElementList) {
+        for (int j = 0; j < propertyElementList.getLength(); j++) {
+            Node pNode = propertyElementList.item(j);
+            if (pNode.getNodeType() != Node.ELEMENT_NODE) {
+                continue;
+            }
+            Element propertyElement = (Element) pNode;
+            if (propertyElement.getNodeName().equals("property")
+                    && currentConfiguration != null) {
+                currentConfiguration.addAttribute(
+                        propertyElement.getAttribute("name"),
+                        propertyElement.getAttribute("value"));
+            }
+        }
+    }
+
+    private void extractSymbolConfig(NodeList symbolTableConfigElementList, String language) throws RedPenException {
+        configBuilder.setLanguage(language);
+
+        NodeList symbolTableElementList =
+                getSpecifiedNodeList((Element)
+                        symbolTableConfigElementList.item(0), "symbol");
+        if (symbolTableElementList == null) {
+            LOG.warn("there is no character block");
+            return;
+        }
+        for (int temp = 0; temp < symbolTableElementList.getLength(); temp++) {
+            Node nNode = symbolTableElementList.item(temp);
+            if (nNode.getNodeType() == Node.ELEMENT_NODE) {
+                Element element = (Element) nNode;
+                Symbol currentSymbol = createSymbol(element);
+                configBuilder.addSymbol(currentSymbol);
+            }
+        }
+    }
+
+    private NodeList getSpecifiedNodeList(Element rootElement, String elementName) {
+        NodeList elementList =
+                rootElement.getElementsByTagName(elementName);
+        if (elementList.getLength() == 0) {
+            LOG.info("No \"" +
+                    elementName + "\" block found in the configuration");
+            return null;
+        } else if (elementList.getLength() > 1) {
+            LOG.info("More than one \"" + elementName + " \" blocks in the configuration");
+        }
+        return elementList;
+    }
+
+    private Element getRootNode(Document doc, String rootTag) {
+        doc.getDocumentElement().normalize();
+        NodeList rootConfigElementList =
+                doc.getElementsByTagName(rootTag);
+        if (rootConfigElementList.getLength() == 0) {
+            throw new IllegalStateException("No \"" + rootTag
+                    + "\" block found in the configuration");
+        } else if (rootConfigElementList.getLength() > 1) {
+            LOG.warn("More than one \"" +
+                    rootTag + "\" blocks in the configuration");
+        }
+        Node root = rootConfigElementList.item(0);
+        Element rootElement = (Element) root;
+        LOG.info("Succeeded to load configuration file");
+        return rootElement;
+    }
+}
diff --git a/redpen-core/src/main/java/cc/redpen/config/SymbolTable.java b/redpen-core/src/main/java/cc/redpen/config/SymbolTable.java
index 0e5f36a2..ec6e682e 100644
--- a/redpen-core/src/main/java/cc/redpen/config/SymbolTable.java
+++ b/redpen-core/src/main/java/cc/redpen/config/SymbolTable.java
@@ -31,8 +31,8 @@ import static cc.redpen.config.SymbolType.*;
  */
 public class SymbolTable implements Serializable, Cloneable {
     private static final long serialVersionUID = 1612920745151501631L;
-    private final Map<SymbolType, Symbol> symbolDictionary = new HashMap<>();
-    private final Map<Character, Symbol> valueDictionary = new HashMap<>();
+    private final Map<SymbolType, Symbol> symbolDictionary = new LinkedHashMap<>();
+    private final Map<Character, Symbol> valueDictionary = new LinkedHashMap<>();
     private String variant;
     private String lang;
     private static final Logger LOG = LoggerFactory.getLogger(SymbolTable.class);
@@ -43,26 +43,29 @@ public class SymbolTable implements Serializable, Cloneable {
     SymbolTable(String lang, Optional<String> variant, List<Symbol> customSymbols) {
         this.lang = lang;
         this.variant = variant.orElse("");
+        getDefaultSymbols().values().forEach(this::overrideSymbol);
+        customSymbols.forEach(this::overrideSymbol);
+    }
+
+    public Map<SymbolType, Symbol> getDefaultSymbols() {
         if (lang.equals("ja")) {
             LOG.info("\"ja\" is specified.");
-            if (this.variant.equals("hankaku")) {
-                LOG.info("\"hankaku\" variant is specified");
-                JAPANESE_HANKAKU_SYMBOLS.values().forEach(this::overrideSymbol);
-            } else if (this.variant.equals("zenkaku2")) {
-                LOG.info("\"zenkaku2\" variant is specified");
-                JAPANESE_SYMBOLS.values().forEach(this::overrideSymbol);
-                this.overrideSymbol(new Symbol(FULL_STOP, '．', "。."));
-                this.overrideSymbol(new Symbol(COMMA, '，', "、,"));
-            } else {
-                this.variant = "zenkaku";
-                LOG.info("\"zenkaku\" variant is specified");
-                JAPANESE_SYMBOLS.values().forEach(this::overrideSymbol);
+            switch (this.variant) {
+                case "hankaku":
+                    LOG.info("\"hankaku\" variant is specified");
+                    return JAPANESE_HANKAKU_SYMBOLS;
+                case "zenkaku2":
+                    LOG.info("\"zenkaku2\" variant is specified");
+                    return JAPANESE_ZENKAKU2_SYMBOLS;
+                default:
+                    this.variant = "zenkaku";
+                    LOG.info("\"zenkaku\" variant is specified");
+                    return JAPANESE_SYMBOLS;
             }
         } else {
             LOG.info("Default symbol settings are loaded");
-            DEFAULT_SYMBOLS.values().forEach(this::overrideSymbol);
+            return DEFAULT_SYMBOLS;
         }
-        customSymbols.forEach(this::overrideSymbol);
     }
 
     /**
@@ -182,10 +185,11 @@ public class SymbolTable implements Serializable, Cloneable {
 
     private static final Map<SymbolType, Symbol> DEFAULT_SYMBOLS;
     private static final Map<SymbolType, Symbol> JAPANESE_SYMBOLS;
+    private static final Map<SymbolType, Symbol> JAPANESE_ZENKAKU2_SYMBOLS;
     private static final Map<SymbolType, Symbol> JAPANESE_HANKAKU_SYMBOLS;
 
     private static Map<SymbolType, Symbol> initializeSymbols(Symbol... newSymbols) {
-        HashMap<SymbolType, Symbol> symbolTypeSymbolMap = new HashMap<>();
+        Map<SymbolType, Symbol> symbolTypeSymbolMap = new LinkedHashMap<>();
         for (Symbol symbol : newSymbols) {
             symbolTypeSymbolMap.put(symbol.getType(), symbol);
         }
@@ -292,6 +296,10 @@ public class SymbolTable implements Serializable, Cloneable {
                 , new Symbol(DIGIT_EIGHT, '8', "")
                 , new Symbol(DIGIT_NINE, '9', ""));
 
+        JAPANESE_ZENKAKU2_SYMBOLS = new LinkedHashMap<>(JAPANESE_SYMBOLS);
+        JAPANESE_ZENKAKU2_SYMBOLS.put(FULL_STOP, new Symbol(FULL_STOP, '．', "。."));
+        JAPANESE_ZENKAKU2_SYMBOLS.put(COMMA, new Symbol(COMMA, '，', "、,"));
+
         JAPANESE_HANKAKU_SYMBOLS = initializeSymbols(
                 new Symbol(SPACE, '　', " ")
                 , new Symbol(EXCLAMATION_MARK, '!', "！")
@@ -340,5 +348,4 @@ public class SymbolTable implements Serializable, Cloneable {
                 , new Symbol(DIGIT_EIGHT, '8', "８")
                 , new Symbol(DIGIT_NINE, '9', "９"));
     }
-
 }
diff --git a/redpen-core/src/main/java/cc/redpen/package-info.java b/redpen-core/src/main/java/cc/redpen/package-info.java
index 40f124e7..f8841779 100644
--- a/redpen-core/src/main/java/cc/redpen/package-info.java
+++ b/redpen-core/src/main/java/cc/redpen/package-info.java
@@ -1,5 +1,5 @@
 /**
- * contains {@link cc.redpen.RedPen} Main class and some important classes used thought
+ * contains {@link cc.redpen.RedPen} Main class and some important classes used throughout
  * the project.
  */
 package cc.redpen;
diff --git a/redpen-core/src/main/java/cc/redpen/util/IndentingXMLStreamWriter.java b/redpen-core/src/main/java/cc/redpen/util/IndentingXMLStreamWriter.java
new file mode 100644
index 00000000..2e03042b
--- /dev/null
+++ b/redpen-core/src/main/java/cc/redpen/util/IndentingXMLStreamWriter.java
@@ -0,0 +1,158 @@
+package cc.redpen.util;
+
+import javax.xml.namespace.NamespaceContext;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamWriter;
+
+import static org.apache.commons.lang3.StringUtils.repeat;
+
+public class IndentingXMLStreamWriter implements XMLStreamWriter {
+  XMLStreamWriter delegate;
+  int level;
+
+  public IndentingXMLStreamWriter(XMLStreamWriter delegate) {
+    this.delegate = delegate;
+  }
+
+  private void writeIndent() throws XMLStreamException {
+    delegate.writeCharacters("\n" + repeat("\t", level));
+  }
+
+  @Override public void writeEmptyElement(String localName) throws XMLStreamException {
+    if (level > 0) writeIndent();
+    delegate.writeEmptyElement(localName);
+  }
+
+  @Override public void writeStartElement(String localName) throws XMLStreamException {
+    if (level > 0) writeIndent();
+    delegate.writeStartElement(localName);
+    level++;
+  }
+
+  @Override public void writeEndElement() throws XMLStreamException {
+    level--;
+    writeIndent();
+    delegate.writeEndElement();
+  }
+
+  // delegated methods
+
+  @Override public void close() throws XMLStreamException {
+    delegate.close();
+  }
+
+  @Override public void flush() throws XMLStreamException {
+    delegate.flush();
+  }
+
+  @Override public NamespaceContext getNamespaceContext() {
+    return delegate.getNamespaceContext();
+  }
+
+  @Override public String getPrefix(String uri) throws XMLStreamException {
+    return delegate.getPrefix(uri);
+  }
+
+  @Override public Object getProperty(String name) throws IllegalArgumentException {
+    return delegate.getProperty(name);
+  }
+
+  @Override public void setDefaultNamespace(String uri) throws XMLStreamException {
+    delegate.setDefaultNamespace(uri);
+  }
+
+  @Override public void setNamespaceContext(NamespaceContext context) throws XMLStreamException {
+    delegate.setNamespaceContext(context);
+  }
+
+  @Override public void setPrefix(String prefix, String uri) throws XMLStreamException {
+    delegate.setPrefix(prefix, uri);
+  }
+
+  @Override public void writeAttribute(String localName, String value) throws XMLStreamException {
+    delegate.writeAttribute(localName, value);
+  }
+
+  @Override public void writeAttribute(String namespaceURI, String localName, String value) throws XMLStreamException {
+    delegate.writeAttribute(namespaceURI, localName, value);
+  }
+
+  @Override
+  public void writeAttribute(String prefix, String namespaceURI, String localName, String value) throws XMLStreamException {
+    delegate.writeAttribute(prefix, namespaceURI, localName, value);
+  }
+
+  @Override public void writeCData(String data) throws XMLStreamException {
+    delegate.writeCData(data);
+  }
+
+  @Override public void writeCharacters(char[] text, int start, int len) throws XMLStreamException {
+    delegate.writeCharacters(text, start, len);
+  }
+
+  @Override public void writeCharacters(String text) throws XMLStreamException {
+    delegate.writeCharacters(text);
+  }
+
+  @Override public void writeComment(String data) throws XMLStreamException {
+    delegate.writeComment(data);
+  }
+
+  @Override public void writeDefaultNamespace(String namespaceURI) throws XMLStreamException {
+    delegate.writeDefaultNamespace(namespaceURI);
+  }
+
+  @Override public void writeDTD(String dtd) throws XMLStreamException {
+    delegate.writeDTD(dtd);
+  }
+
+  @Override public void writeEmptyElement(String namespaceURI, String localName) throws XMLStreamException {
+    delegate.writeEmptyElement(namespaceURI, localName);
+  }
+
+  @Override
+  public void writeEmptyElement(String prefix, String localName, String namespaceURI) throws XMLStreamException {
+    delegate.writeEmptyElement(prefix, localName, namespaceURI);
+  }
+
+  @Override public void writeEndDocument() throws XMLStreamException {
+    delegate.writeEndDocument();
+  }
+
+  @Override public void writeEntityRef(String name) throws XMLStreamException {
+    delegate.writeEntityRef(name);
+  }
+
+  @Override public void writeNamespace(String prefix, String namespaceURI) throws XMLStreamException {
+    delegate.writeNamespace(prefix, namespaceURI);
+  }
+
+  @Override public void writeProcessingInstruction(String target) throws XMLStreamException {
+    delegate.writeProcessingInstruction(target);
+  }
+
+  @Override public void writeProcessingInstruction(String target, String data) throws XMLStreamException {
+    delegate.writeProcessingInstruction(target, data);
+  }
+
+  @Override public void writeStartDocument() throws XMLStreamException {
+    delegate.writeStartDocument();
+  }
+
+  @Override public void writeStartDocument(String encoding, String version) throws XMLStreamException {
+    delegate.writeStartDocument(encoding, version);
+  }
+
+  @Override public void writeStartDocument(String version) throws XMLStreamException {
+    delegate.writeStartDocument(version);
+  }
+
+  @Override public void writeStartElement(String namespaceURI, String localName) throws XMLStreamException {
+    delegate.writeStartElement(namespaceURI, localName);
+  }
+
+  @Override
+  public void writeStartElement(String prefix, String localName, String namespaceURI) throws XMLStreamException {
+    delegate.writeStartElement(prefix, localName, namespaceURI);
+  }
+}
diff --git a/redpen-server/src/main/java/cc/redpen/server/api/RedPenResource.java b/redpen-server/src/main/java/cc/redpen/server/api/RedPenResource.java
index afdb815f..d7672851 100644
--- a/redpen-server/src/main/java/cc/redpen/server/api/RedPenResource.java
+++ b/redpen-server/src/main/java/cc/redpen/server/api/RedPenResource.java
@@ -18,9 +18,9 @@
 
 package cc.redpen.server.api;
 
-import cc.redpen.ConfigurationLoader;
 import cc.redpen.RedPen;
 import cc.redpen.RedPenException;
+import cc.redpen.config.ConfigurationLoader;
 import cc.redpen.config.Symbol;
 import cc.redpen.config.SymbolType;
 import cc.redpen.formatter.Formatter;


Test patch:
diff --git a/redpen-core/src/test/java/cc/redpen/config/ConfigurationExporterTest.java b/redpen-core/src/test/java/cc/redpen/config/ConfigurationExporterTest.java
new file mode 100644
index 00000000..efcdf998
--- /dev/null
+++ b/redpen-core/src/test/java/cc/redpen/config/ConfigurationExporterTest.java
@@ -0,0 +1,90 @@
+package cc.redpen.config;
+
+import org.junit.After;
+import org.junit.Test;
+
+import java.io.ByteArrayOutputStream;
+
+import static cc.redpen.config.SymbolType.*;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+public class ConfigurationExporterTest {
+  ConfigurationExporter exporter = new ConfigurationExporter();
+  ByteArrayOutputStream out = new ByteArrayOutputStream();
+
+  @After
+  public void assertConfigIsLoadable() throws Exception {
+    assertNotNull(new ConfigurationLoader().loadFromString(out.toString()));
+  }
+
+  @Test
+  public void emptyConfig() throws Exception {
+    Configuration config = new Configuration.ConfigurationBuilder().build();
+    exporter.export(config, out);
+    assertEquals("<redpen-conf lang=\"en\">\n</redpen-conf>", out.toString());
+  }
+
+  @Test
+  public void emptyConfigForJapaneseLanguage() throws Exception {
+    Configuration config = new Configuration.ConfigurationBuilder().setLanguage("ja").build();
+    exporter.export(config, out);
+    assertEquals("<redpen-conf lang=\"ja\" variant=\"zenkaku\">\n</redpen-conf>", out.toString());
+  }
+
+  @Test
+  public void validators() throws Exception {
+    Configuration config = new Configuration.ConfigurationBuilder()
+      .addValidatorConfig(new ValidatorConfiguration("Mega"))
+      .addValidatorConfig(new ValidatorConfiguration("Super").addAttribute("hello", "world")).build();
+    exporter.export(config, out);
+    assertEquals(
+      "<redpen-conf lang=\"en\">\n" +
+        "	<validators>\n" +
+        "		<validator name=\"Mega\"/>\n" +
+        "		<validator name=\"Super\">\n" +
+        "			<property name=\"hello\" value=\"world\"/>\n" +
+        "		</validator>\n" +
+        "	</validators>\n" +
+        "</redpen-conf>", out.toString());
+  }
+
+  @Test
+  public void symbols() throws Exception {
+    Configuration config = new Configuration.ConfigurationBuilder()
+      .addSymbol(new Symbol(ASTERISK, 'X'))
+      .addSymbol(new Symbol(COLON, ';', ":", false, true))
+      .addSymbol(new Symbol(SEMICOLON, ':', ";&", true, false)).build();
+
+    exporter.export(config, out);
+
+    assertEquals(
+      "<redpen-conf lang=\"en\">\n" +
+        "	<symbols>\n" +
+        "		<symbol name=\"ASTERISK\" value=\"X\"/>\n" +
+        "		<symbol name=\"COLON\" value=\";\" invalid-chars=\":\" after-space=\"true\"/>\n" +
+        "		<symbol name=\"SEMICOLON\" value=\":\" invalid-chars=\";&amp;\" before-space=\"true\"/>\n" +
+        "	</symbols>\n" +
+        "</redpen-conf>", out.toString());
+  }
+
+  @Test
+  public void generatedConfigIsLoadable() throws Exception {
+    String config = "<redpen-conf lang=\"en\">\n" +
+      "	<validators>\n" +
+      "		<validator name=\"SentenceLength\">\n" +
+      "			<property name=\"max_len\" value=\"100\"/>\n" +
+      "		</validator>\n" +
+      "		<validator name=\"InvalidSymbol\"/>\n" +
+      "	</validators>\n" +
+      "	<symbols>\n" +
+      "		<symbol name=\"EXCLAMATION_MARK\" value=\"！\" invalid-chars=\"!\" after-space=\"true\"/>\n" +
+      "	</symbols>\n" +
+      "</redpen-conf>";
+    Configuration configuration = new ConfigurationLoader().loadFromString(config);
+
+    exporter.export(configuration, out);
+
+    assertEquals(config, out.toString());
+  }
+}
\ No newline at end of file
diff --git a/redpen-core/src/test/java/cc/redpen/ConfigurationLoaderTest.java b/redpen-core/src/test/java/cc/redpen/config/ConfigurationLoaderTest.java
similarity index 75%
rename from redpen-core/src/test/java/cc/redpen/ConfigurationLoaderTest.java
rename to redpen-core/src/test/java/cc/redpen/config/ConfigurationLoaderTest.java
index 0585a466..7631ad47 100644
--- a/redpen-core/src/test/java/cc/redpen/ConfigurationLoaderTest.java
+++ b/redpen-core/src/test/java/cc/redpen/config/ConfigurationLoaderTest.java
@@ -15,48 +15,22 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package cc.redpen;
+package cc.redpen.config;
 
-import cc.redpen.config.Configuration;
+import cc.redpen.RedPenException;
 import org.junit.Test;
 
 import static cc.redpen.config.SymbolType.*;
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
 
 public class ConfigurationLoaderTest {
     @Test
-    public void testLoadConfiguration() throws RedPenException{
-        String sampleConfigString =
-                "<redpen-conf lang=\"en\">" +
-                        "<validators>" +
-                        "<validator name=\"SentenceLength\">" +
-                        "<property name=\"max_length\" value=\"200\" />" +
-                        "</validator>" +
-                        "<validator name=\"MaxParagraphNumber\" />" +
-                        "</validators>" +
-                        "<symbols>" +
-                        "<symbol name=\"EXCLAMATION_MARK\" value=\"!\" invalid-chars=\"！\" after-space=\"true\" />" +
-                        "</symbols>" +
-                        "</redpen-conf>";
-
-        ConfigurationLoader configurationLoader = new ConfigurationLoader();
-        Configuration configuration = configurationLoader.loadFromString(sampleConfigString);
+    public void emptyConfiguration() throws RedPenException {
+        Configuration configuration = new ConfigurationLoader().loadFromString("<redpen-conf/>");
 
         assertNotNull(configuration);
-        assertEquals(2, configuration.getValidatorConfigs().size());
-        assertEquals("SentenceLength",
-                configuration.getValidatorConfigs().get(0).getConfigurationName());
-        assertEquals("200",
-                configuration.getValidatorConfigs().get(0).getAttribute("max_length"));
-        assertEquals("MaxParagraphNumber",
-                configuration.getValidatorConfigs().get(1).getConfigurationName());
-        assertNotNull(configuration.getSymbolTable());
-        assertEquals('!', configuration.getSymbolTable()
-                .getSymbol(EXCLAMATION_MARK).getValue());
-        assertEquals(1, configuration.getSymbolTable()
-                .getSymbol(EXCLAMATION_MARK).getInvalidChars().length);
-        assertEquals('！', configuration.getSymbolTable()
-                .getSymbol(EXCLAMATION_MARK).getInvalidChars()[0]);
+        assertEquals("en", configuration.getLang());
     }
 
     @Test
@@ -74,8 +48,7 @@ public class ConfigurationLoaderTest {
                         "</symbols>" +
                         "</redpen-conf>";
 
-        ConfigurationLoader configurationLoader = new ConfigurationLoader();
-        Configuration configuration = configurationLoader.loadFromString(sampleConfigString);
+        Configuration configuration = new ConfigurationLoader().loadFromString(sampleConfigString);
 
         assertNotNull(configuration);
         assertEquals("zenkaku", configuration.getVariant());
@@ -107,8 +80,7 @@ public class ConfigurationLoaderTest {
                         "</validators>" +
                         "</redpen-conf>";
 
-        ConfigurationLoader configurationLoader = new ConfigurationLoader();
-        Configuration configuration = configurationLoader.loadFromString(sampleConfigString);
+        Configuration configuration = new ConfigurationLoader().loadFromString(sampleConfigString);
 
         assertNotNull(configuration);
         assertEquals("hankaku", configuration.getVariant());
@@ -132,8 +104,7 @@ public class ConfigurationLoaderTest {
     public void testVariantCanBeSpecifiedAsTypeForBackwardsCompatibility() throws RedPenException{
         String sampleConfigString = "<redpen-conf lang=\"ja\" type=\"hankaku\"><validators/></redpen-conf>";
 
-        ConfigurationLoader configurationLoader = new ConfigurationLoader();
-        Configuration configuration = configurationLoader.loadFromString(sampleConfigString);
+        Configuration configuration = new ConfigurationLoader().loadFromString(sampleConfigString);
 
         assertEquals("hankaku", configuration.getVariant());
     }
@@ -150,8 +121,7 @@ public class ConfigurationLoaderTest {
                         "</validators>" +
                         "</redpen-conf>";
 
-        ConfigurationLoader configurationLoader = new ConfigurationLoader();
-        Configuration configuration = configurationLoader.loadFromString(sampleConfigString);
+        Configuration configuration = new ConfigurationLoader().loadFromString(sampleConfigString);
 
         assertNotNull(configuration);
         assertEquals("zenkaku2", configuration.getVariant());
@@ -185,8 +155,7 @@ public class ConfigurationLoaderTest {
                         "</validators>" +
                         "</redpen-conf>";
 
-        ConfigurationLoader configurationLoader = new ConfigurationLoader();
-        Configuration configuration = configurationLoader.loadFromString(sampleConfigString);
+        Configuration configuration = new ConfigurationLoader().loadFromString(sampleConfigString);
 
         assertNotNull(configuration);
         assertEquals("en", configuration.getLang());
@@ -213,8 +182,7 @@ public class ConfigurationLoaderTest {
                         "<symbols/>" +
                         "</redpen-conf>";
 
-        ConfigurationLoader configurationLoader = new ConfigurationLoader();
-        Configuration configuration = configurationLoader.loadFromString(sampleConfigString);
+        Configuration configuration = new ConfigurationLoader().loadFromString(sampleConfigString);
 
         assertNotNull(configuration);
         assertEquals(2, configuration.getValidatorConfigs().size());
@@ -227,20 +195,6 @@ public class ConfigurationLoaderTest {
                 .getSymbol(EXCLAMATION_MARK).getValue());
     }
 
-    @Test
-    public void testNewLoadConfigurationWithoutValidatorConfig() throws RedPenException {
-        String sampleConfigString =
-                "<redpen-conf lang=\"en\">" +
-                        "<symbols>" +
-                        "<symbol name=\"EXCLAMATION_MARK\" value=\"!\" invalid-chars=\"！\" after-space=\"true\" />" +
-                        "</symbols>" +
-                        "</redpen-conf>";
-
-        ConfigurationLoader configurationLoader = new ConfigurationLoader();
-        Configuration configuration = configurationLoader.loadFromString(sampleConfigString);
-        assertNull(configuration);
-    }
-
     @Test
     public void testNewLoadConfigurationWithoutValidatorConfigContent() throws RedPenException{
         String sampleConfigString =
@@ -252,20 +206,10 @@ public class ConfigurationLoaderTest {
                         "</symbols>" +
                         "</redpen-conf>";
 
-        ConfigurationLoader configurationLoader = new ConfigurationLoader();
-        Configuration configuration = configurationLoader.loadFromString(sampleConfigString);
+        Configuration configuration = new ConfigurationLoader().loadFromString(sampleConfigString);
         assertNotNull(configuration);
     }
 
-    @Test
-    public void testVoidConfig() throws RedPenException{
-        String sampleConfigString =
-                "<redpen-conf></redpen-conf>";
-        ConfigurationLoader configurationLoader = new ConfigurationLoader();
-        Configuration configuration = configurationLoader.loadFromString(sampleConfigString);
-        assertNull(configuration);
-    }
-
     @Test(expected = RedPenException.class)
     public void testNewLoadInvalidConfiguration() throws RedPenException{
         String sampleConfigString =
@@ -281,9 +225,8 @@ public class ConfigurationLoaderTest {
                         "</symbols>" +
                         "<redpen-conf>";  // NOTE: Invalid xml since slash should be exist.
 
-        ConfigurationLoader configurationLoader = new ConfigurationLoader();
         // expecting RedPenException
-        configurationLoader.loadFromString(sampleConfigString);
+        new ConfigurationLoader().loadFromString(sampleConfigString);
     }
 
     @Test
@@ -299,8 +242,7 @@ public class ConfigurationLoaderTest {
                         "</symbols>" +
                         "</redpen-conf>";
 
-        ConfigurationLoader configurationLoader = new ConfigurationLoader();
-        Configuration configuration = configurationLoader.loadFromString(sampleConfigString);
+        Configuration configuration = new ConfigurationLoader().loadFromString(sampleConfigString);
 
         assertNotNull(configuration);
 
@@ -329,8 +271,7 @@ public class ConfigurationLoaderTest {
                         "</symbols>" +
                         "</redpen-conf>";
 
-        ConfigurationLoader configurationLoader = new ConfigurationLoader();
-        Configuration configuration = configurationLoader.loadFromString(sampleConfigString);
+        Configuration configuration = new ConfigurationLoader().loadFromString(sampleConfigString);
 
         assertNotNull(configuration);
 
@@ -346,7 +287,6 @@ public class ConfigurationLoaderTest {
                 .getSymbol(EXCLAMATION_MARK).isNeedAfterSpace());
     }
 
-
     @Test
     public void testConfigurationMultipleInvalids() throws RedPenException{
         String sampleConfigString =
@@ -360,8 +300,7 @@ public class ConfigurationLoaderTest {
                         "</symbols>" +
                         "</redpen-conf>";
 
-        ConfigurationLoader configurationLoader = new ConfigurationLoader();
-        Configuration configuration = configurationLoader.loadFromString(sampleConfigString);
+        Configuration configuration = new ConfigurationLoader().loadFromString(sampleConfigString);
 
         assertNotNull(configuration);
 
@@ -386,8 +325,7 @@ public class ConfigurationLoaderTest {
                         "</symbols>" +
                         "</redpen-conf>";
 
-        ConfigurationLoader configurationLoader = new ConfigurationLoader();
-        Configuration configuration = configurationLoader.loadFromString(sampleConfigString);
+        Configuration configuration = new ConfigurationLoader().loadFromString(sampleConfigString);
 
         assertNotNull(configuration);
 
@@ -414,8 +352,7 @@ public class ConfigurationLoaderTest {
                         "</symbols>" +
                         "</redpen-conf>";
 
-        ConfigurationLoader configurationLoader = new ConfigurationLoader();
-        Configuration configuration = configurationLoader.loadFromString(sampleConfigString);
+        Configuration configuration = new ConfigurationLoader().loadFromString(sampleConfigString);
 
         assertNotNull(configuration);
 //        // NOTE: HADOOP_CHARACTER does not exist even in default settings
@@ -423,7 +360,6 @@ public class ConfigurationLoaderTest {
 //        assertNull(ch);
     }
 
-
     @Test
     public void testConfigurationWithMisspelledBlock() throws RedPenException{
         String sampleConfigString =
@@ -437,8 +373,7 @@ public class ConfigurationLoaderTest {
                         "</symbols>" +
                         "</redpen-conf>";
 
-        ConfigurationLoader configurationLoader = new ConfigurationLoader();
-        Configuration configuration = configurationLoader.loadFromString(sampleConfigString);
+        Configuration configuration = new ConfigurationLoader().loadFromString(sampleConfigString);
         assertNotNull(configuration); //FIXME: should be null or throw a exception. This will be fixed with issue #133.
         assertNotNull(configuration.getSymbolTable());
     }
@@ -456,8 +391,7 @@ public class ConfigurationLoaderTest {
                         "</symbols>" +
                         "</redpen-conf>";
 
-        ConfigurationLoader configurationLoader = new ConfigurationLoader();
-        configurationLoader.loadFromString(sampleConfigString);
+        new ConfigurationLoader().loadFromString(sampleConfigString);
     }
 
 }