diff --git a/config/findbugs-exclude.xml b/config/findbugs-exclude.xml
index 0f14231..7040fb5 100644
--- a/config/findbugs-exclude.xml
+++ b/config/findbugs-exclude.xml
@@ -27,4 +27,9 @@
         <Class name="~.*\.Immutable.*"/>
         <Bug pattern="NP_METHOD_PARAMETER_TIGHTENS_ANNOTATION"/>
     </Match>
+    <Match>
+        <!-- We can't change generated source code. -->
+        <Class name="~.*\.GsonAdapters.*"/>
+        <Bug pattern="URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD"/>
+    </Match>
 </FindBugsFilter>
diff --git a/config/sevntu_suppressions.xml b/config/sevntu_suppressions.xml
index 96c88d8..13a051b 100644
--- a/config/sevntu_suppressions.xml
+++ b/config/sevntu_suppressions.xml
@@ -4,5 +4,5 @@
         "http://www.puppycrawl.com/dtds/suppressions_1_1.dtd">
 
 <suppressions>
-    <suppress checks="MultipleStringLiteralsExtended" files=".*[\\/]src[\\/]test[\\/]"/>
+    <suppress checks="MultipleStringLiteralsExtended" files="[\\/]ExtractInfoGeneratorTest.java$|.*[\\/]src[\\/]test[\\/]"/>
 </suppressions>
diff --git a/config/suppressions.xml b/config/suppressions.xml
index fc75af3..523ae74 100644
--- a/config/suppressions.xml
+++ b/config/suppressions.xml
@@ -13,7 +13,7 @@
     <suppress checks="MagicNumber" files=".*[\\/]src[\\/]test[\\/]"/>
     <suppress checks="AvoidStaticImport" files=".*[\\/]src[\\/]test[\\/]"/>
     <suppress checks="WriteTag" files=".*[\\/]src[\\/]test[\\/]"/>
-    <suppress checks="MultipleStringLiterals" files=".*[\\/]src[\\/]test[\\/]"/>
+    <suppress checks="MultipleStringLiterals" files="[\\/]ExtractInfoGeneratorTest.java$|.*[\\/]src[\\/]test[\\/]"/>
 
     <suppress checks="AbstractClassName" files=".*[\\/]data[\\/]"/>
 </suppressions>
diff --git a/src/main/java/com/github/checkstyle/regression/data/ModuleExtractInfo.java b/src/main/java/com/github/checkstyle/regression/data/ModuleExtractInfo.java
index 22566cf..aa7d429 100644
--- a/src/main/java/com/github/checkstyle/regression/data/ModuleExtractInfo.java
+++ b/src/main/java/com/github/checkstyle/regression/data/ModuleExtractInfo.java
@@ -19,6 +19,8 @@
 
 package com.github.checkstyle.regression.data;
 
+import java.util.List;
+
 import org.immutables.gson.Gson;
 import org.immutables.value.Value;
 
@@ -48,6 +50,12 @@ public abstract class ModuleExtractInfo {
      */
     public abstract String parent();
 
+    /**
+     * The properties of this module.
+     * @return the properties of this module
+     */
+    public abstract List<ModuleProperty> properties();
+
     /**
      * The full qualified name of this module.
      * @return the full qualified name of this module
@@ -55,4 +63,33 @@ public abstract class ModuleExtractInfo {
     public String fullName() {
         return packageName() + "." + name();
     }
+
+    /** Represents a property of checkstyle module. */
+    @Gson.TypeAdapters
+    @Value.Immutable
+    public interface ModuleProperty {
+        /**
+         * The name of this property.
+         * @return the name of this property
+         */
+        String name();
+
+        /**
+         * The type of this property.
+         * The value should be one of the followings:
+         *     - Pattern
+         *     - SeverityLevel
+         *     - boolean
+         *     - Scope
+         *     - double[]
+         *     - int[]
+         *     - String[]
+         *     - String
+         *     - URI
+         *     - AccessModifier[]
+         *     - int
+         * @return the type of this property
+         */
+        String type();
+    }
 }
diff --git a/src/main/resources/com/github/checkstyle/regression/extract/ExtractInfoGeneratorTest.java b/src/main/resources/com/github/checkstyle/regression/extract/ExtractInfoGeneratorTest.java
index f7f2790..f135592 100644
--- a/src/main/resources/com/github/checkstyle/regression/extract/ExtractInfoGeneratorTest.java
+++ b/src/main/resources/com/github/checkstyle/regression/extract/ExtractInfoGeneratorTest.java
@@ -19,8 +19,8 @@
 
 package com.puppycrawl.tools.checkstyle;
 
+import java.beans.PropertyDescriptor;
 import java.io.File;
-import java.io.IOException;
 import java.nio.charset.Charset;
 import java.nio.file.Files;
 import java.nio.file.StandardOpenOption;
@@ -28,10 +28,17 @@
 import java.util.Arrays;
 import java.util.Comparator;
 import java.util.List;
+import java.util.Set;
+import java.util.TreeSet;
 
+import org.apache.commons.beanutils.PropertyUtils;
 import org.junit.Test;
 
+import com.puppycrawl.tools.checkstyle.api.AbstractCheck;
+import com.puppycrawl.tools.checkstyle.api.AbstractFileSetCheck;
+import com.puppycrawl.tools.checkstyle.checks.javadoc.AbstractJavadocCheck;
 import com.puppycrawl.tools.checkstyle.internal.CheckUtil;
+import com.puppycrawl.tools.checkstyle.internal.TestUtils;
 import com.puppycrawl.tools.checkstyle.utils.ModuleReflectionUtils;
 
 /**
@@ -40,12 +47,57 @@
  * @author LuoLiangchen
  */
 public class ExtractInfoGeneratorTest {
+    /** Modules which do not have global properties to drop. */
+    private static final List<String> XML_FILESET_LIST = Arrays.asList(
+            "TreeWalker",
+            "Checker",
+            "Header",
+            "Translation",
+            "SeverityMatchFilter",
+            "SuppressionFilter",
+            "SuppressWarningsFilter",
+            "BeforeExecutionExclusionFileFilter",
+            "RegexpHeader",
+            "RegexpOnFilename",
+            "RegexpSingleline",
+            "RegexpMultiline",
+            "JavadocPackage",
+            "NewlineAtEndOfFile",
+            "UniqueProperties",
+            "FileLength",
+            "FileTabCharacter"
+    );
+
+    /** Properties of abstract check. */
+    private static final Set<String> CHECK_PROPERTIES = getProperties(AbstractCheck.class);
+
+    /** Properties of abstract Javadoc check. */
+    private static final Set<String> JAVADOC_CHECK_PROPERTIES =
+            getProperties(AbstractJavadocCheck.class);
+
+    /** Properties of abstract file-set check. */
+    private static final Set<String> FILESET_PROPERTIES = getProperties(AbstractFileSetCheck.class);
+
+    /** Properties without document. */
+    private static final List<String> UNDOCUMENTED_PROPERTIES = Arrays.asList(
+            "Checker.classLoader",
+            "Checker.classloader",
+            "Checker.moduleClassLoader",
+            "Checker.moduleFactory",
+            "TreeWalker.classLoader",
+            "TreeWalker.moduleFactory",
+            "TreeWalker.cacheFile",
+            "TreeWalker.upChild",
+            "SuppressWithNearbyCommentFilter.fileContents",
+            "SuppressionCommentFilter.fileContents"
+    );
+
     /**
      * Generates the extract info file named as "checkstyle_modules.json".
-     * @throws IOException failure when generating the file
+     * @throws Exception failure when generating the file
      */
     @Test
-    public void generateExtractInfoFile() throws IOException {
+    public void generateExtractInfoFile() throws Exception {
         final List<Class<?>> modules = new ArrayList<>(CheckUtil.getCheckstyleModules());
         modules.sort(Comparator.comparing(Class::getSimpleName));
         final JsonUtil.JsonArray moduleJsonArray = new JsonUtil.JsonArray();
@@ -62,8 +114,10 @@ public void generateExtractInfoFile() throws IOException {
      * Creates Json object for a module from the module class.
      * @param clazz the given module class
      * @return the Json object describing the extract info of the module
+     * @throws Exception failure when creating Json object
      */
-    private static JsonUtil.JsonObject createJsonObjectFromModuleClass(Class<?> clazz) {
+    private static JsonUtil.JsonObject createJsonObjectFromModuleClass(Class<?> clazz)
+            throws Exception {
         final JsonUtil.JsonObject object = new JsonUtil.JsonObject();
 
         final String name = clazz.getSimpleName();
@@ -94,6 +148,116 @@ else if (ModuleReflectionUtils.isRootModule(clazz)) {
         object.add("interfaces", interfaces);
         object.add("hierarchies", hierarchies);
 
+        final JsonUtil.JsonArray properties = new JsonUtil.JsonArray();
+        for (String propertyName : getNecessaryProperties(clazz)) {
+            final JsonUtil.JsonObject property = new JsonUtil.JsonObject();
+            property.addProperty("name", propertyName);
+            Arrays.stream(PropertyUtils.getPropertyDescriptors(clazz))
+                    .filter(p -> p.getName().equals(propertyName))
+                    .map(PropertyDescriptor::getPropertyType)
+                    .map(Class::getSimpleName)
+                    .findAny()
+                    .ifPresent(type -> property.addProperty("type", type));
+            properties.add(property);
+        }
+        object.add("properties", properties);
+
         return object;
     }
+
+    /**
+     * Gets the necessary properties of a checkstyle module.
+     * Global properties and undocumented properties are not necessary for us.
+     * @param clazz the class instance of the given module
+     * @return a set of the necessary properties of the module
+     * @throws Exception failure when getting properties
+     */
+    // -@cs[CyclomaticComplexity] many different kinds of module
+    private static Set<String> getNecessaryProperties(Class<?> clazz)
+            throws Exception {
+        final Set<String> properties = getProperties(clazz);
+        if (hasParentModule(clazz.getSimpleName())) {
+            if (AbstractJavadocCheck.class.isAssignableFrom(clazz)) {
+                properties.removeAll(JAVADOC_CHECK_PROPERTIES);
+            }
+            else if (ModuleReflectionUtils.isCheckstyleCheck(clazz)) {
+                properties.removeAll(CHECK_PROPERTIES);
+            }
+        }
+        if (ModuleReflectionUtils.isFileSetModule(clazz)) {
+            properties.removeAll(FILESET_PROPERTIES);
+
+            // override
+            properties.add("fileExtensions");
+        }
+
+        // undocumented properties are not necessary
+        properties.removeIf(prop -> UNDOCUMENTED_PROPERTIES.contains(
+                clazz.getSimpleName() + "." + prop));
+
+        final PackageObjectFactory factory = TestUtils.getPackageObjectFactory();
+        final Object instance = factory.createModule(clazz.getSimpleName());
+
+        if (ModuleReflectionUtils.isCheckstyleCheck(clazz)) {
+            final AbstractCheck check = (AbstractCheck) instance;
+
+            final int[] acceptableTokens = check.getAcceptableTokens();
+            Arrays.sort(acceptableTokens);
+            final int[] defaultTokens = check.getDefaultTokens();
+            Arrays.sort(defaultTokens);
+            final int[] requiredTokens = check.getRequiredTokens();
+            Arrays.sort(requiredTokens);
+
+            if (!Arrays.equals(acceptableTokens, defaultTokens)
+                    || !Arrays.equals(acceptableTokens, requiredTokens)) {
+                properties.add("tokens");
+            }
+        }
+
+        if (AbstractJavadocCheck.class.isAssignableFrom(clazz)) {
+            final AbstractJavadocCheck check = (AbstractJavadocCheck) instance;
+
+            final int[] acceptableJavadocTokens = check.getAcceptableJavadocTokens();
+            Arrays.sort(acceptableJavadocTokens);
+            final int[] defaultJavadocTokens = check.getDefaultJavadocTokens();
+            Arrays.sort(defaultJavadocTokens);
+            final int[] requiredJavadocTokens = check.getRequiredJavadocTokens();
+            Arrays.sort(requiredJavadocTokens);
+
+            if (!Arrays.equals(acceptableJavadocTokens, defaultJavadocTokens)
+                    || !Arrays.equals(acceptableJavadocTokens, requiredJavadocTokens)) {
+                properties.add("javadocTokens");
+            }
+        }
+
+        return properties;
+    }
+
+    /**
+     * Gets the properties of a checkstyle module.
+     * @param clazz the class instance of the given module
+     * @return a set of the properties of the module
+     */
+    private static Set<String> getProperties(Class<?> clazz) {
+        final Set<String> result = new TreeSet<>();
+        final PropertyDescriptor[] map = PropertyUtils.getPropertyDescriptors(clazz);
+
+        for (PropertyDescriptor p : map) {
+            if (p.getWriteMethod() != null) {
+                result.add(p.getName());
+            }
+        }
+
+        return result;
+    }
+
+    /**
+     * Checks whether a module has a parent that may contains global properties.
+     * @param className the class name of given module
+     * @return true if the module has a parent
+     */
+    private static boolean hasParentModule(String className) {
+        return !XML_FILESET_LIST.contains(className) && XML_FILESET_LIST.stream()
+                .map(name -> name + "Check").noneMatch(name -> name.equals(className));
+    }
 }
diff --git a/src/test/java/com/github/checkstyle/regression/extract/ExtractInfoProcessorTest.java b/src/test/java/com/github/checkstyle/regression/extract/ExtractInfoProcessorTest.java
index 6f8262a..146c83a 100644
--- a/src/test/java/com/github/checkstyle/regression/extract/ExtractInfoProcessorTest.java
+++ b/src/test/java/com/github/checkstyle/regression/extract/ExtractInfoProcessorTest.java
@@ -38,6 +38,7 @@
 import org.junit.Test;
 
 import com.github.checkstyle.regression.data.ImmutableModuleExtractInfo;
+import com.github.checkstyle.regression.data.ImmutableModuleProperty;
 import com.github.checkstyle.regression.data.ModuleExtractInfo;
 
 public class ExtractInfoProcessorTest {
@@ -69,6 +70,14 @@ public void testGetModuleExtractInfosFromReader() throws Exception {
                 .name(module1)
                 .packageName(BASE_PACKAGE + ".checks")
                 .parent("Checker")
+                .addProperties(ImmutableModuleProperty.builder()
+                        .name("fileExtensions")
+                        .type("String[]")
+                        .build())
+                .addProperties(ImmutableModuleProperty.builder()
+                        .name("lineSeparator")
+                        .type("String")
+                        .build())
                 .build();
         final String module2 = "EmptyStatementCheck";
         final ModuleExtractInfo extractInfo2 = ImmutableModuleExtractInfo.builder()
diff --git a/src/test/java/com/github/checkstyle/regression/module/ModuleInfoCollectorTest.java b/src/test/java/com/github/checkstyle/regression/module/ModuleInfoCollectorTest.java
index ce3466d..a5603e3 100644
--- a/src/test/java/com/github/checkstyle/regression/module/ModuleInfoCollectorTest.java
+++ b/src/test/java/com/github/checkstyle/regression/module/ModuleInfoCollectorTest.java
@@ -39,6 +39,7 @@
 import com.github.checkstyle.regression.data.ImmutableGitChange;
 import com.github.checkstyle.regression.data.ImmutableModuleExtractInfo;
 import com.github.checkstyle.regression.data.ImmutableModuleInfo;
+import com.github.checkstyle.regression.data.ImmutableModuleProperty;
 import com.github.checkstyle.regression.data.ModuleExtractInfo;
 import com.github.checkstyle.regression.data.ModuleInfo;
 import com.github.checkstyle.regression.extract.ExtractInfoProcessor;
@@ -117,6 +118,14 @@ public void testGenerateConfigNodesForValidChanges2() {
                 .name("NewlineAtEndOfFileCheck")
                 .packageName(BASE_PACKAGE + ".checks")
                 .parent("Checker")
+                .addProperties(ImmutableModuleProperty.builder()
+                        .name("fileExtensions")
+                        .type("String[]")
+                        .build())
+                .addProperties(ImmutableModuleProperty.builder()
+                        .name("lineSeparator")
+                        .type("String")
+                        .build())
                 .build();
         final List<ModuleInfo> moduleInfos =
                 ModuleCollector.generate(changes);
diff --git a/src/test/resources/checkstyle_modules.json b/src/test/resources/checkstyle_modules.json
index 8a28051..6864da0 100644
--- a/src/test/resources/checkstyle_modules.json
+++ b/src/test/resources/checkstyle_modules.json
@@ -12,6 +12,16 @@
       "com.puppycrawl.tools.checkstyle.api.FileSetCheck",
       "com.puppycrawl.tools.checkstyle.api.Configurable",
       "com.puppycrawl.tools.checkstyle.api.Contextualizable"
+    ],
+    "properties": [
+      {
+        "name": "fileExtensions",
+        "type": "String[]"
+      },
+      {
+        "name": "lineSeparator",
+        "type": "String"
+      }
     ]
   },
   {
@@ -26,6 +36,9 @@
     "interfaces": [
       "com.puppycrawl.tools.checkstyle.api.Configurable",
       "com.puppycrawl.tools.checkstyle.api.Contextualizable"
+    ],
+    "properties": [
+
     ]
   }
 ]