geode-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From jinmeil...@apache.org
Subject [geode] branch develop updated: GEODE-3915: use ClassName type for cache-loader, writer and listeners (#1327)
Date Mon, 29 Jan 2018 19:21:35 GMT
This is an automated email from the ASF dual-hosted git repository.

jinmeiliao pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/geode.git


The following commit(s) were added to refs/heads/develop by this push:
     new d0fef0f  GEODE-3915: use ClassName type for cache-loader, writer and listeners (#1327)
d0fef0f is described below

commit d0fef0f07889b2e38d8a56d751d7934afd38ea09
Author: jinmeiliao <jiliao@pivotal.io>
AuthorDate: Mon Jan 29 11:21:32 2018 -0800

    GEODE-3915: use ClassName type for cache-loader, writer and listeners (#1327)
    
    * GEODE-3915: use ClassName type for cache-loader, writer and listeners
    
    * use json string to specify the init properties
    * make sure the parser works when multiple ClassNames are specified in the command line.
    * rework AlterRegionCommandDUnitTest
    * make sure AnalyzeSerializableJunitTest works in IDEA.
    
    Signed-off-by: Patrick Rhomberg <prhomberg@pivotal.io>
---
 .../geode/management/internal/cli/GfshParser.java  |  59 +-
 .../internal/cli/commands/AlterRegionCommand.java  |  36 +-
 .../internal/cli/commands/CreateRegionCommand.java |  45 +-
 .../internal/cli/commands/RegionCommandsUtils.java |   9 -
 .../cli/converters/ClassNameConverter.java         |  62 +++
 .../management/internal/cli/domain/ClassName.java  | 124 +++++
 .../cli/functions/RegionAlterFunction.java         |  52 +-
 .../cli/functions/RegionCreateFunction.java        |  24 +-
 .../internal/cli/functions/RegionFunctionArgs.java |  58 +-
 .../sanctioned-geode-core-serializables.txt        |   3 +-
 .../AnalyzeSerializablesJUnitTest.java             |  13 +-
 .../internal/cli/GfshParserJUnitTest.java          |  17 +
 .../internal/cli/GfshParserParsingTest.java        |  10 -
 .../cli/commands/AlterRegionCommandDUnitTest.java  | 592 ++-------------------
 .../AlterRegionCommandIntegrationTest.java         |   9 +-
 .../cli/commands/AlterRegionCommandTest.java       |  66 +++
 .../CreateRegionCommandIntegrationTest.java        |  15 +-
 .../cli/commands/CreateRegionCommandTest.java      | 127 ++++-
 .../cli/commands/ShutdownCommandDUnitTest.java     |  52 +-
 .../cli/converters/ClassNameConverterTest.java     |  87 +++
 .../internal/cli/domain/ClassNameTest.java         | 115 ++++
 .../internal/cli/domain/MyCacheWriter.java         |  33 ++
 22 files changed, 830 insertions(+), 778 deletions(-)

diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/GfshParser.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/GfshParser.java
index 4fc7d4e..67447c2 100755
--- a/geode-core/src/main/java/org/apache/geode/management/internal/cli/GfshParser.java
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/GfshParser.java
@@ -17,8 +17,6 @@ package org.apache.geode.management.internal.cli;
 import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.List;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
 
 import org.apache.commons.lang.StringUtils;
 import org.springframework.shell.converters.ArrayConverter;
@@ -48,10 +46,6 @@ public class GfshParser extends SimpleParser {
   public static final String J_ARGUMENT_DELIMITER = "" + ASCII_UNIT_SEPARATOR;
   public static final String J_OPTION_CONTEXT = "splittingRegex=" + J_ARGUMENT_DELIMITER;
 
-  // pattern used to split the user input with whitespaces except those in quotes (single or double)
-  private static Pattern PATTERN =
-      Pattern.compile("\\s*([^\\s']*)'([^']*)'\\s+|\\s*([^\\s\"]*)\"([^\"]*)\"\\s+|\\S+");
-
   public GfshParser(CommandManager commandManager) {
     for (CommandMarker command : commandManager.getCommandMarkers()) {
       add(command);
@@ -71,16 +65,53 @@ public class GfshParser extends SimpleParser {
     return getSimpleParserInputFromTokens(inputTokens);
   }
 
+  /**
+   * it's assumed that the quoted string should not have escaped quotes inside it.
+   */
+  public static List<String> splitWithWhiteSpace(String input) {
+    List<String> tokensList = new ArrayList<>();
+    StringBuilder token = new StringBuilder();
+    char insideQuoteOf = Character.MIN_VALUE;
+
+    for (char c : input.toCharArray()) {
+      if (Character.isWhitespace(c)) {
+        // if we are in the quotes
+        if (insideQuoteOf != Character.MIN_VALUE) {
+          token.append(c);
+        }
+        // if we are not in the quotes, terminate this token and add it to the list
+        else {
+          if (token.length() > 0) {
+            tokensList.add(token.toString());
+          }
+          token = new StringBuilder();
+        }
+      }
+      // not a white space
+      else {
+        token.append(c);
+        // if encountering a quote
+        if (c == '\'' || c == '\"') {
+          // if this is the beginning of quote
+          if (insideQuoteOf == Character.MIN_VALUE) {
+            insideQuoteOf = c;
+          }
+          // this is the ending of quote
+          else if (insideQuoteOf == c) {
+            insideQuoteOf = Character.MIN_VALUE;
+          }
+        }
+      }
+    }
+    if (token.length() > 0) {
+      tokensList.add(token.toString());
+    }
+    return tokensList;
+  }
+
   static List<String> splitUserInput(String userInput) {
-    // make sure the userInput ends with a white space, because our regex expects the the quotes
-    // ends with at least one white space. We will trim the results after we found it.
-    userInput = userInput + " ";
     // first split with whitespaces except in quotes
-    List<String> splitWithWhiteSpaces = new ArrayList<>();
-    Matcher m = PATTERN.matcher(userInput);
-    while (m.find()) {
-      splitWithWhiteSpaces.add(m.group().trim());
-    }
+    List<String> splitWithWhiteSpaces = splitWithWhiteSpace(userInput);
 
     List<String> furtherSplitWithEquals = new ArrayList<>();
     for (String token : splitWithWhiteSpaces) {
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/AlterRegionCommand.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/AlterRegionCommand.java
index 37da04e..86a38c0 100644
--- a/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/AlterRegionCommand.java
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/AlterRegionCommand.java
@@ -20,11 +20,15 @@ import java.util.Set;
 import org.springframework.shell.core.annotation.CliCommand;
 import org.springframework.shell.core.annotation.CliOption;
 
+import org.apache.geode.cache.CacheListener;
+import org.apache.geode.cache.CacheLoader;
+import org.apache.geode.cache.CacheWriter;
 import org.apache.geode.distributed.DistributedMember;
 import org.apache.geode.internal.cache.InternalCache;
 import org.apache.geode.management.cli.CliMetaData;
 import org.apache.geode.management.cli.ConverterHint;
 import org.apache.geode.management.cli.Result;
+import org.apache.geode.management.internal.cli.domain.ClassName;
 import org.apache.geode.management.internal.cli.functions.CliFunctionResult;
 import org.apache.geode.management.internal.cli.functions.RegionAlterFunction;
 import org.apache.geode.management.internal.cli.functions.RegionFunctionArgs;
@@ -64,11 +68,13 @@ public class AlterRegionCommand implements GfshCommand {
           specifiedDefaultValue = "INVALIDATE",
           help = CliStrings.ALTER_REGION__REGIONEXPIRATIONTTLACTION__HELP) String regionExpirationTTLAction,
       @CliOption(key = CliStrings.ALTER_REGION__CACHELISTENER, specifiedDefaultValue = "",
-          help = CliStrings.ALTER_REGION__CACHELISTENER__HELP) String[] cacheListeners,
+          // split the input only with comma outside of json string
+          optionContext = "splittingRegex=,(?![^{]*\\})",
+          help = CliStrings.ALTER_REGION__CACHELISTENER__HELP) ClassName<CacheListener>[] cacheListeners,
       @CliOption(key = CliStrings.ALTER_REGION__CACHELOADER, specifiedDefaultValue = "",
-          help = CliStrings.ALTER_REGION__CACHELOADER__HELP) String cacheLoader,
+          help = CliStrings.ALTER_REGION__CACHELOADER__HELP) ClassName<CacheLoader> cacheLoader,
       @CliOption(key = CliStrings.ALTER_REGION__CACHEWRITER, specifiedDefaultValue = "",
-          help = CliStrings.ALTER_REGION__CACHEWRITER__HELP) String cacheWriter,
+          help = CliStrings.ALTER_REGION__CACHEWRITER__HELP) ClassName<CacheWriter> cacheWriter,
       @CliOption(key = CliStrings.ALTER_REGION__ASYNCEVENTQUEUEID, specifiedDefaultValue = "",
           help = CliStrings.ALTER_REGION__ASYNCEVENTQUEUEID__HELP) String[] asyncEventQueueIds,
       @CliOption(key = CliStrings.ALTER_REGION__GATEWAYSENDERID, specifiedDefaultValue = "",
@@ -103,30 +109,6 @@ public class AlterRegionCommand implements GfshCommand {
     regionFunctionArgs.setCloningEnabled(cloningEnabled);
     regionFunctionArgs.setEvictionMax(evictionMax);
 
-
-    Set<String> cacheListenersSet = regionFunctionArgs.getCacheListeners();
-    if (cacheListenersSet != null && !cacheListenersSet.isEmpty()) {
-      for (String cacheListener : cacheListenersSet) {
-        if (!RegionCommandsUtils.isClassNameValid(cacheListener)) {
-          throw new IllegalArgumentException(CliStrings.format(
-              CliStrings.ALTER_REGION__MSG__SPECIFY_VALID_CLASSNAME_FOR_CACHELISTENER_0_IS_INVALID,
-              cacheListener));
-        }
-      }
-    }
-
-    if (cacheLoader != null && !RegionCommandsUtils.isClassNameValid(cacheLoader)) {
-      throw new IllegalArgumentException(CliStrings.format(
-          CliStrings.ALTER_REGION__MSG__SPECIFY_VALID_CLASSNAME_FOR_CACHELOADER_0_IS_INVALID,
-          cacheLoader));
-    }
-
-    if (cacheWriter != null && !RegionCommandsUtils.isClassNameValid(cacheWriter)) {
-      throw new IllegalArgumentException(CliStrings.format(
-          CliStrings.ALTER_REGION__MSG__SPECIFY_VALID_CLASSNAME_FOR_CACHEWRITER_0_IS_INVALID,
-          cacheWriter));
-    }
-
     if (evictionMax != null && evictionMax < 0) {
       throw new IllegalArgumentException(CliStrings.format(
           CliStrings.ALTER_REGION__MSG__SPECIFY_POSITIVE_INT_FOR_EVICTIONMAX_0_IS_NOT_VALID,
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/CreateRegionCommand.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/CreateRegionCommand.java
index c3b6aa5..5cae312 100644
--- a/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/CreateRegionCommand.java
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/CreateRegionCommand.java
@@ -25,6 +25,9 @@ import javax.management.ObjectName;
 import org.springframework.shell.core.annotation.CliCommand;
 import org.springframework.shell.core.annotation.CliOption;
 
+import org.apache.geode.cache.CacheListener;
+import org.apache.geode.cache.CacheLoader;
+import org.apache.geode.cache.CacheWriter;
 import org.apache.geode.cache.DataPolicy;
 import org.apache.geode.cache.EvictionAction;
 import org.apache.geode.cache.Region;
@@ -46,6 +49,7 @@ import org.apache.geode.management.internal.cli.AbstractCliAroundInterceptor;
 import org.apache.geode.management.internal.cli.CliUtil;
 import org.apache.geode.management.internal.cli.GfshParseResult;
 import org.apache.geode.management.internal.cli.LogWrapper;
+import org.apache.geode.management.internal.cli.domain.ClassName;
 import org.apache.geode.management.internal.cli.functions.CliFunctionResult;
 import org.apache.geode.management.internal.cli.functions.FetchRegionAttributesFunction;
 import org.apache.geode.management.internal.cli.functions.RegionCreateFunction;
@@ -88,11 +92,13 @@ public class CreateRegionCommand implements GfshCommand {
       @CliOption(key = CliStrings.CREATE_REGION__ASYNCEVENTQUEUEID,
           help = CliStrings.CREATE_REGION__ASYNCEVENTQUEUEID__HELP) String[] asyncEventQueueIds,
       @CliOption(key = CliStrings.CREATE_REGION__CACHELISTENER,
-          help = CliStrings.CREATE_REGION__CACHELISTENER__HELP) String[] cacheListener,
+          // split the input only with "," outside of json string
+          optionContext = "splittingRegex=,(?![^{]*\\})",
+          help = CliStrings.CREATE_REGION__CACHELISTENER__HELP) ClassName<CacheListener>[] cacheListener,
       @CliOption(key = CliStrings.CREATE_REGION__CACHELOADER,
-          help = CliStrings.CREATE_REGION__CACHELOADER__HELP) String cacheLoader,
+          help = CliStrings.CREATE_REGION__CACHELOADER__HELP) ClassName<CacheLoader> cacheLoader,
       @CliOption(key = CliStrings.CREATE_REGION__CACHEWRITER,
-          help = CliStrings.CREATE_REGION__CACHEWRITER__HELP) String cacheWriter,
+          help = CliStrings.CREATE_REGION__CACHEWRITER__HELP) ClassName<CacheWriter> cacheWriter,
       @CliOption(key = CliStrings.CREATE_REGION__COLOCATEDWITH,
           optionContext = ConverterHint.REGION_PATH,
           help = CliStrings.CREATE_REGION__COLOCATEDWITH__HELP) String prColocatedWith,
@@ -559,7 +565,7 @@ public class CreateRegionCommand implements GfshCommand {
 
       String keyConstraint =
           parseResult.getParamValueAsString(CliStrings.CREATE_REGION__KEYCONSTRAINT);
-      if (keyConstraint != null && !RegionCommandsUtils.isClassNameValid(keyConstraint)) {
+      if (keyConstraint != null && !ClassName.isClassNameValid(keyConstraint)) {
         return ResultBuilder.createUserErrorResult(CliStrings.format(
             CliStrings.CREATE_REGION__MSG__SPECIFY_VALID_CLASSNAME_FOR_KEYCONSTRAINT_0_IS_INVALID,
             new Object[] {keyConstraint}));
@@ -567,41 +573,14 @@ public class CreateRegionCommand implements GfshCommand {
 
       String valueConstraint =
           parseResult.getParamValueAsString(CliStrings.CREATE_REGION__VALUECONSTRAINT);
-      if (valueConstraint != null && !RegionCommandsUtils.isClassNameValid(valueConstraint)) {
+      if (valueConstraint != null && !ClassName.isClassNameValid(valueConstraint)) {
         return ResultBuilder.createUserErrorResult(CliStrings.format(
             CliStrings.CREATE_REGION__MSG__SPECIFY_VALID_CLASSNAME_FOR_VALUECONSTRAINT_0_IS_INVALID,
             new Object[] {valueConstraint}));
       }
 
-      String cacheListenerList =
-          parseResult.getParamValueAsString(CliStrings.CREATE_REGION__CACHELISTENER);
-      if (cacheListenerList != null) {
-        String[] cacheListeners = cacheListenerList.split(",");
-        for (String cacheListener : cacheListeners) {
-          if (!RegionCommandsUtils.isClassNameValid(cacheListener)) {
-            return ResultBuilder.createUserErrorResult(CliStrings.format(
-                CliStrings.CREATE_REGION__MSG__SPECIFY_VALID_CLASSNAME_FOR_CACHELISTENER_0_IS_INVALID,
-                new Object[] {cacheListener}));
-          }
-        }
-      }
-
-      String cacheLoader = parseResult.getParamValueAsString(CliStrings.CREATE_REGION__CACHELOADER);
-      if (cacheLoader != null && !RegionCommandsUtils.isClassNameValid(cacheLoader)) {
-        return ResultBuilder.createUserErrorResult(CliStrings.format(
-            CliStrings.CREATE_REGION__MSG__SPECIFY_VALID_CLASSNAME_FOR_CACHELOADER_0_IS_INVALID,
-            new Object[] {cacheLoader}));
-      }
-
-      String cacheWriter = parseResult.getParamValueAsString(CliStrings.CREATE_REGION__CACHEWRITER);
-      if (cacheWriter != null && !RegionCommandsUtils.isClassNameValid(cacheWriter)) {
-        return ResultBuilder.createUserErrorResult(CliStrings.format(
-            CliStrings.CREATE_REGION__MSG__SPECIFY_VALID_CLASSNAME_FOR_CACHEWRITER_0_IS_INVALID,
-            new Object[] {cacheWriter}));
-      }
-
       String compressor = parseResult.getParamValueAsString(CliStrings.CREATE_REGION__COMPRESSOR);
-      if (compressor != null && !RegionCommandsUtils.isClassNameValid(compressor)) {
+      if (compressor != null && !ClassName.isClassNameValid(compressor)) {
         return ResultBuilder.createUserErrorResult(CliStrings
             .format(CliStrings.CREATE_REGION__MSG__INVALID_COMPRESSOR, new Object[] {compressor}));
       }
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/RegionCommandsUtils.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/RegionCommandsUtils.java
index 1885b92..90fbec6 100644
--- a/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/RegionCommandsUtils.java
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/RegionCommandsUtils.java
@@ -21,7 +21,6 @@ import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
 import java.util.TreeSet;
-import java.util.regex.Pattern;
 
 import org.apache.geode.cache.RegionShortcut;
 import org.apache.geode.distributed.DistributedMember;
@@ -67,12 +66,4 @@ public class RegionCommandsUtils {
     }
   }
 
-  static boolean isClassNameValid(String fqcn) {
-    if (fqcn.isEmpty()) {
-      return true;
-    }
-    String regex = "([\\p{L}_$][\\p{L}\\p{N}_$]*\\.)*[\\p{L}_$][\\p{L}\\p{N}_$]*";
-    return Pattern.matches(regex, fqcn);
-  }
-
 }
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/converters/ClassNameConverter.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/converters/ClassNameConverter.java
new file mode 100644
index 0000000..17aa951
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/converters/ClassNameConverter.java
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You 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 org.apache.geode.management.internal.cli.converters;
+
+import java.util.List;
+
+import org.springframework.shell.core.Completion;
+import org.springframework.shell.core.Converter;
+import org.springframework.shell.core.MethodTarget;
+
+import org.apache.geode.management.internal.cli.domain.ClassName;
+
+/**
+ * Used by Gfsh command options that converts a string to a ClassName Object
+ *
+ * User can specify either a classname alone or a className followed by a "?" and json properties to
+ * initialize the object
+ *
+ * e.g. --cache-loader=my.app.CacheLoader
+ * --cache-loader=my.app.CacheLoader?{"param1":"value1","param2":"value2"}
+ *
+ * Currently, if you specify a json properties after the className, the class needs to be a
+ * Declarable for it to be initialized, otherwise, the properties are ignored.
+ *
+ */
+public class ClassNameConverter implements Converter<ClassName> {
+  @Override
+  public boolean supports(Class<?> type, String optionContext) {
+    return ClassName.class.isAssignableFrom(type);
+  }
+
+  @Override
+  public ClassName convertFromText(String value, Class<?> targetType, String optionContext) {
+    int index = value.indexOf('{');
+    if (index < 0) {
+      return new ClassName(value);
+    } else {
+      String className = value.substring(0, index);
+      String json = value.substring(index);
+      return new ClassName(className, json);
+    }
+  }
+
+  @Override
+  public boolean getAllPossibleValues(List<Completion> completions, Class<?> targetType,
+      String existingData, String optionContext, MethodTarget target) {
+    return false;
+  }
+}
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/domain/ClassName.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/domain/ClassName.java
new file mode 100644
index 0000000..3641d74
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/domain/ClassName.java
@@ -0,0 +1,124 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You 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 org.apache.geode.management.internal.cli.domain;
+
+import java.io.IOException;
+import java.io.Serializable;
+import java.util.Properties;
+import java.util.regex.Pattern;
+
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.apache.commons.lang.StringUtils;
+
+import org.apache.geode.cache.Declarable;
+import org.apache.geode.internal.ClassPathLoader;
+
+/**
+ * This is mostly used for Gfsh command options that need to specify a className for instantiation.
+ *
+ * See ClassNameConverter.
+ */
+public class ClassName<T> implements Serializable {
+  private static final long serialVersionUID = 1L;
+
+  private String className = "";
+  private Properties initProperties = new Properties();
+  private static ObjectMapper mapper = new ObjectMapper();
+
+  static {
+    mapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
+  }
+
+  // used to remove a Declarable through gfsh command
+  // e.g. alter region --name=regionA --cache-loader=''
+  public static ClassName EMPTY = new ClassName("");
+
+  /**
+   * Object to be instantiated using the empty param constructor of the className
+   *
+   * @param className this class needs to have an empty param constructor
+   */
+  public ClassName(String className) {
+    this(className, "{}");
+  }
+
+  /**
+   *
+   * @param className this class needs to have an empty param constructor
+   * @param jsonInitProperties this class needs to implement Declarable in order for these
+   *        properties to be applied at initialization time
+   */
+  public ClassName(String className, String jsonInitProperties) {
+    if (StringUtils.isBlank(className)) {
+      return;
+    }
+    if (!isClassNameValid(className)) {
+      throw new IllegalArgumentException("Invalid className");
+    }
+    this.className = className;
+    try {
+      initProperties = mapper.readValue(jsonInitProperties, Properties.class);
+    } catch (IOException e) {
+      throw new IllegalArgumentException("Invalid JSON: " + jsonInitProperties, e);
+    }
+  }
+
+  public String getClassName() {
+    return className;
+  }
+
+  public Properties getInitProperties() {
+    return initProperties;
+  }
+
+  public static boolean isClassNameValid(String fqcn) {
+    if (StringUtils.isBlank(fqcn)) {
+      return false;
+    }
+    String regex = "([\\p{L}_$][\\p{L}\\p{N}_$]*\\.)*[\\p{L}_$][\\p{L}\\p{N}_$]*";
+    return Pattern.matches(regex, fqcn);
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (o == null) {
+      return false;
+    }
+
+    if (!(o instanceof ClassName)) {
+      return false;
+    }
+
+    ClassName that = (ClassName) o;
+
+    return this.className.equals(that.getClassName())
+        && this.getInitProperties().equals(that.getInitProperties());
+  }
+
+  public T newInstance() {
+    try {
+      Class<T> loadedClass = (Class<T>) ClassPathLoader.getLatest().forName(className);
+      T object = loadedClass.newInstance();
+      if (object instanceof Declarable) {
+        ((Declarable) object).init(initProperties);
+      }
+      return object;
+    } catch (Exception e) {
+      throw new RuntimeException("Error instantiating class: <" + className + ">", e);
+    }
+  }
+}
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/functions/RegionAlterFunction.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/functions/RegionAlterFunction.java
index 47c2897..c604258 100644
--- a/geode-core/src/main/java/org/apache/geode/management/internal/cli/functions/RegionAlterFunction.java
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/functions/RegionAlterFunction.java
@@ -38,6 +38,7 @@ import org.apache.geode.internal.cache.AbstractRegion;
 import org.apache.geode.internal.cache.xmlcache.CacheXml;
 import org.apache.geode.internal.logging.LogService;
 import org.apache.geode.management.internal.cli.CliUtil;
+import org.apache.geode.management.internal.cli.domain.ClassName;
 import org.apache.geode.management.internal.cli.i18n.CliStrings;
 import org.apache.geode.management.internal.cli.util.RegionPath;
 import org.apache.geode.management.internal.configuration.domain.XmlEntity;
@@ -224,51 +225,34 @@ public class RegionAlterFunction implements Function, InternalEntity {
     }
 
     // Alter Cache Listeners
-    final Set<String> newCacheListenerNames = regionAlterArgs.getCacheListeners();
-    if (newCacheListenerNames != null) {
+    final Set<ClassName<CacheListener>> newCacheListeners = regionAlterArgs.getCacheListeners();
 
-      // Remove old cache listeners that aren't in the new list
+    // user specified a new set of cache listeners
+    if (newCacheListeners != null) {
+      // remove the old ones, even if the new set includes the same class name, the init properties
+      // might be different
       CacheListener[] oldCacheListeners = region.getCacheListeners();
       for (CacheListener oldCacheListener : oldCacheListeners) {
-        if (!newCacheListenerNames.contains(oldCacheListener.getClass().getName())) {
-          mutator.removeCacheListener(oldCacheListener);
-        }
+        mutator.removeCacheListener(oldCacheListener);
       }
 
-      // Add new cache listeners that don't already exist
-      for (String newCacheListenerName : newCacheListenerNames) {
-        if (newCacheListenerName.isEmpty()) {
-          continue;
-        }
-        boolean nameFound = false;
-        for (CacheListener oldCacheListener : oldCacheListeners) {
-          if (oldCacheListener.getClass().getName().equals(newCacheListenerName)) {
-            nameFound = true;
-            break;
-          }
-        }
-
-        if (!nameFound) {
-          Class<CacheListener<K, V>> cacheListenerKlass =
-              forName(newCacheListenerName, CliStrings.ALTER_REGION__CACHELISTENER);
-          mutator.addCacheListener(
-              newInstance(cacheListenerKlass, CliStrings.ALTER_REGION__CACHELISTENER));
+      // Add new cache listeners
+      for (ClassName<CacheListener> newCacheListener : newCacheListeners) {
+        if (!newCacheListener.equals(ClassName.EMPTY)) {
+          mutator.addCacheListener(newCacheListener.newInstance());
         }
       }
-
       if (logger.isDebugEnabled()) {
         logger.debug("Region successfully altered - cache listeners");
       }
     }
 
-    final String cacheLoader = regionAlterArgs.getCacheLoader();
+    final ClassName<CacheLoader> cacheLoader = regionAlterArgs.getCacheLoader();
     if (cacheLoader != null) {
-      if (cacheLoader.isEmpty()) {
+      if (cacheLoader.equals(ClassName.EMPTY)) {
         mutator.setCacheLoader(null);
       } else {
-        Class<CacheLoader<K, V>> cacheLoaderKlass =
-            forName(cacheLoader, CliStrings.ALTER_REGION__CACHELOADER);
-        mutator.setCacheLoader(newInstance(cacheLoaderKlass, CliStrings.ALTER_REGION__CACHELOADER));
+        mutator.setCacheLoader(cacheLoader.newInstance());
       }
 
       if (logger.isDebugEnabled()) {
@@ -276,14 +260,12 @@ public class RegionAlterFunction implements Function, InternalEntity {
       }
     }
 
-    final String cacheWriter = regionAlterArgs.getCacheWriter();
+    final ClassName<CacheWriter> cacheWriter = regionAlterArgs.getCacheWriter();
     if (cacheWriter != null) {
-      if (cacheWriter.isEmpty()) {
+      if (cacheWriter.equals(ClassName.EMPTY)) {
         mutator.setCacheWriter(null);
       } else {
-        Class<CacheWriter<K, V>> cacheWriterKlass =
-            forName(cacheWriter, CliStrings.ALTER_REGION__CACHEWRITER);
-        mutator.setCacheWriter(newInstance(cacheWriterKlass, CliStrings.ALTER_REGION__CACHEWRITER));
+        mutator.setCacheWriter(cacheWriter.newInstance());
       }
 
       if (logger.isDebugEnabled()) {
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/functions/RegionCreateFunction.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/functions/RegionCreateFunction.java
index 3c032da..f9fb157 100644
--- a/geode-core/src/main/java/org/apache/geode/management/internal/cli/functions/RegionCreateFunction.java
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/functions/RegionCreateFunction.java
@@ -50,6 +50,7 @@ import org.apache.geode.internal.i18n.LocalizedStrings;
 import org.apache.geode.internal.logging.LogService;
 import org.apache.geode.management.internal.cli.CliUtil;
 import org.apache.geode.management.internal.cli.commands.RegionCommandsUtils;
+import org.apache.geode.management.internal.cli.domain.ClassName;
 import org.apache.geode.management.internal.cli.i18n.CliStrings;
 import org.apache.geode.management.internal.cli.util.RegionPath;
 import org.apache.geode.management.internal.configuration.domain.XmlEntity;
@@ -281,14 +282,11 @@ public class RegionCreateFunction implements Function, InternalEntity {
     }
 
     // Set plugins
-    final Set<String> cacheListeners = regionCreateArgs.getCacheListeners();
+    final Set<ClassName<CacheListener>> cacheListeners = regionCreateArgs.getCacheListeners();
     if (cacheListeners != null && !cacheListeners.isEmpty()) {
       List<CacheListener<K, V>> newListeners = new ArrayList<>();
-      for (String cacheListener : cacheListeners) {
-        Class<CacheListener<K, V>> cacheListenerKlass =
-            CliUtil.forName(cacheListener, CliStrings.CREATE_REGION__CACHELISTENER);
-        newListeners
-            .add(CliUtil.newInstance(cacheListenerKlass, CliStrings.CREATE_REGION__CACHELISTENER));
+      for (ClassName<CacheListener> cacheListener : cacheListeners) {
+        newListeners.add(cacheListener.newInstance());
       }
       factory.initCacheListeners(newListeners.toArray(new CacheListener[0]));
     }
@@ -301,20 +299,14 @@ public class RegionCreateFunction implements Function, InternalEntity {
           CliUtil.newInstance(compressorKlass, CliStrings.CREATE_REGION__COMPRESSOR));
     }
 
-    final String cacheLoader = regionCreateArgs.getCacheLoader();
+    final ClassName<CacheLoader> cacheLoader = regionCreateArgs.getCacheLoader();
     if (cacheLoader != null) {
-      Class<CacheLoader<K, V>> cacheLoaderKlass =
-          CliUtil.forName(cacheLoader, CliStrings.CREATE_REGION__CACHELOADER);
-      factory.setCacheLoader(
-          CliUtil.newInstance(cacheLoaderKlass, CliStrings.CREATE_REGION__CACHELOADER));
+      factory.setCacheLoader(cacheLoader.newInstance());
     }
 
-    final String cacheWriter = regionCreateArgs.getCacheWriter();
+    final ClassName<CacheWriter> cacheWriter = regionCreateArgs.getCacheWriter();
     if (cacheWriter != null) {
-      Class<CacheWriter<K, V>> cacheWriterKlass =
-          CliUtil.forName(cacheWriter, CliStrings.CREATE_REGION__CACHEWRITER);
-      factory.setCacheWriter(
-          CliUtil.newInstance(cacheWriterKlass, CliStrings.CREATE_REGION__CACHEWRITER));
+      factory.setCacheWriter(cacheWriter.newInstance());
     }
 
     // If a region path indicates a sub-region,
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/functions/RegionFunctionArgs.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/functions/RegionFunctionArgs.java
index 1b2bf5b..1570b23 100644
--- a/geode-core/src/main/java/org/apache/geode/management/internal/cli/functions/RegionFunctionArgs.java
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/functions/RegionFunctionArgs.java
@@ -22,6 +22,9 @@ import java.util.HashSet;
 import java.util.Set;
 import java.util.stream.Collectors;
 
+import org.apache.geode.cache.CacheListener;
+import org.apache.geode.cache.CacheLoader;
+import org.apache.geode.cache.CacheWriter;
 import org.apache.geode.cache.EvictionAction;
 import org.apache.geode.cache.EvictionAttributes;
 import org.apache.geode.cache.ExpirationAction;
@@ -30,6 +33,7 @@ import org.apache.geode.cache.RegionAttributes;
 import org.apache.geode.cache.RegionShortcut;
 import org.apache.geode.cache.util.ObjectSizer;
 import org.apache.geode.internal.ClassPathLoader;
+import org.apache.geode.management.internal.cli.domain.ClassName;
 import org.apache.geode.management.internal.cli.i18n.CliStrings;
 
 /**
@@ -39,7 +43,7 @@ import org.apache.geode.management.internal.cli.i18n.CliStrings;
  * @since GemFire 7.0
  */
 public class RegionFunctionArgs implements Serializable {
-  private static final long serialVersionUID = 2204943186081037301L;
+  private static final long serialVersionUID = 2204943186081037302L;
 
   private String regionPath;
   private RegionShortcut regionShortcut;
@@ -48,18 +52,18 @@ public class RegionFunctionArgs implements Serializable {
   private String keyConstraint;
   private String valueConstraint;
   private Boolean statisticsEnabled;
-  private RegionFunctionArgs.ExpirationAttrs entryExpirationIdleTime;
-  private RegionFunctionArgs.ExpirationAttrs entryExpirationTTL;
-  private RegionFunctionArgs.ExpirationAttrs regionExpirationIdleTime;
-  private RegionFunctionArgs.ExpirationAttrs regionExpirationTTL;
-  private RegionFunctionArgs.EvictionAttrs evictionAttributes;
+  private ExpirationAttrs entryExpirationIdleTime;
+  private ExpirationAttrs entryExpirationTTL;
+  private ExpirationAttrs regionExpirationIdleTime;
+  private ExpirationAttrs regionExpirationTTL;
+  private EvictionAttrs evictionAttributes;
   private String diskStore;
   private Boolean diskSynchronous;
   private Boolean enableAsyncConflation;
   private Boolean enableSubscriptionConflation;
-  private Set<String> cacheListeners = Collections.emptySet();
-  private String cacheLoader;
-  private String cacheWriter;
+  private Set<ClassName<CacheListener>> cacheListeners = Collections.emptySet();
+  private ClassName<CacheLoader> cacheLoader;
+  private ClassName<CacheWriter> cacheWriter;
   private Set<String> asyncEventQueueIds = Collections.emptySet();
   private Set<String> gatewaySenderIds = Collections.emptySet();
   private Boolean concurrencyChecksEnabled;
@@ -107,29 +111,29 @@ public class RegionFunctionArgs implements Serializable {
 
   public void setEntryExpirationIdleTime(Integer timeout, String action) {
     if (timeout != null) {
-      this.entryExpirationIdleTime = new ExpirationAttrs(
-          RegionFunctionArgs.ExpirationAttrs.ExpirationFor.ENTRY_IDLE, timeout, action);
+      this.entryExpirationIdleTime =
+          new ExpirationAttrs(ExpirationAttrs.ExpirationFor.ENTRY_IDLE, timeout, action);
     }
   }
 
   public void setEntryExpirationTTL(Integer timeout, String action) {
     if (timeout != null) {
-      this.entryExpirationTTL = new ExpirationAttrs(
-          RegionFunctionArgs.ExpirationAttrs.ExpirationFor.ENTRY_TTL, timeout, action);
+      this.entryExpirationTTL =
+          new ExpirationAttrs(ExpirationAttrs.ExpirationFor.ENTRY_TTL, timeout, action);
     }
   }
 
   public void setRegionExpirationIdleTime(Integer timeout, String action) {
     if (timeout != null) {
-      this.regionExpirationIdleTime = new ExpirationAttrs(
-          RegionFunctionArgs.ExpirationAttrs.ExpirationFor.REGION_IDLE, timeout, action);
+      this.regionExpirationIdleTime =
+          new ExpirationAttrs(ExpirationAttrs.ExpirationFor.REGION_IDLE, timeout, action);
     }
   }
 
   public void setRegionExpirationTTL(Integer timeout, String action) {
     if (timeout != null) {
-      this.regionExpirationTTL = new ExpirationAttrs(
-          RegionFunctionArgs.ExpirationAttrs.ExpirationFor.REGION_TTL, timeout, action);
+      this.regionExpirationTTL =
+          new ExpirationAttrs(ExpirationAttrs.ExpirationFor.REGION_TTL, timeout, action);
     }
   }
 
@@ -158,17 +162,17 @@ public class RegionFunctionArgs implements Serializable {
     this.enableSubscriptionConflation = enableSubscriptionConflation;
   }
 
-  public void setCacheListeners(String[] cacheListeners) {
+  public void setCacheListeners(ClassName<CacheListener>[] cacheListeners) {
     if (cacheListeners != null) {
       this.cacheListeners = Arrays.stream(cacheListeners).collect(Collectors.toSet());
     }
   }
 
-  public void setCacheLoader(String cacheLoader) {
+  public void setCacheLoader(ClassName<CacheLoader> cacheLoader) {
     this.cacheLoader = cacheLoader;
   }
 
-  public void setCacheWriter(String cacheWriter) {
+  public void setCacheWriter(ClassName<CacheWriter> cacheWriter) {
     this.cacheWriter = cacheWriter;
   }
 
@@ -281,28 +285,28 @@ public class RegionFunctionArgs implements Serializable {
   /**
    * @return the entryExpirationIdleTime
    */
-  public RegionFunctionArgs.ExpirationAttrs getEntryExpirationIdleTime() {
+  public ExpirationAttrs getEntryExpirationIdleTime() {
     return this.entryExpirationIdleTime;
   }
 
   /**
    * @return the entryExpirationTTL
    */
-  public RegionFunctionArgs.ExpirationAttrs getEntryExpirationTTL() {
+  public ExpirationAttrs getEntryExpirationTTL() {
     return this.entryExpirationTTL;
   }
 
   /**
    * @return the regionExpirationIdleTime
    */
-  public RegionFunctionArgs.ExpirationAttrs getRegionExpirationIdleTime() {
+  public ExpirationAttrs getRegionExpirationIdleTime() {
     return this.regionExpirationIdleTime;
   }
 
   /**
    * @return the regionExpirationTTL
    */
-  public RegionFunctionArgs.ExpirationAttrs getRegionExpirationTTL() {
+  public ExpirationAttrs getRegionExpirationTTL() {
     return this.regionExpirationTTL;
   }
 
@@ -341,7 +345,7 @@ public class RegionFunctionArgs implements Serializable {
   /**
    * @return the cacheListeners
    */
-  public Set<String> getCacheListeners() {
+  public Set<ClassName<CacheListener>> getCacheListeners() {
     if (this.cacheListeners == null) {
       return null;
     }
@@ -351,14 +355,14 @@ public class RegionFunctionArgs implements Serializable {
   /**
    * @return the cacheLoader
    */
-  public String getCacheLoader() {
+  public ClassName<CacheLoader> getCacheLoader() {
     return this.cacheLoader;
   }
 
   /**
    * @return the cacheWriter
    */
-  public String getCacheWriter() {
+  public ClassName<CacheWriter> getCacheWriter() {
     return this.cacheWriter;
   }
 
diff --git a/geode-core/src/main/resources/org/apache/geode/internal/sanctioned-geode-core-serializables.txt b/geode-core/src/main/resources/org/apache/geode/internal/sanctioned-geode-core-serializables.txt
index ef11c11..5dc4f57 100644
--- a/geode-core/src/main/resources/org/apache/geode/internal/sanctioned-geode-core-serializables.txt
+++ b/geode-core/src/main/resources/org/apache/geode/internal/sanctioned-geode-core-serializables.txt
@@ -477,6 +477,7 @@ org/apache/geode/management/internal/cli/AbstractCliAroundInterceptor$Response,f
 org/apache/geode/management/internal/cli/CliUtil$DeflaterInflaterData,true,1104813333595216795,data:byte[],dataLength:int
 org/apache/geode/management/internal/cli/domain/AsyncEventQueueDetails,true,1,batchSize:int,diskStoreName:java/lang/String,id:java/lang/String,listener:java/lang/String,listenerProperties:java/util/Properties,maxQueueMemory:int,persistent:boolean
 org/apache/geode/management/internal/cli/domain/CacheServerInfo,true,1,bindAddress:java/lang/String,isRunning:boolean,port:int
+org/apache/geode/management/internal/cli/domain/ClassName,true,1,className:java/lang/String,initProperties:java/util/Properties
 org/apache/geode/management/internal/cli/domain/DataCommandRequest,false,command:java/lang/String,key:java/lang/String,keyClass:java/lang/String,loadOnCacheMiss:boolean,principal:java/lang/Object,putIfAbsent:boolean,query:java/lang/String,recursive:boolean,regionName:java/lang/String,removeAllKeys:java/lang/String,value:java/lang/String,valueClass:java/lang/String
 org/apache/geode/management/internal/cli/domain/DataCommandResult,true,1,command:java/lang/String,error:java/lang/Throwable,errorString:java/lang/String,getResult:java/lang/Object,hasResultForAggregation:boolean,infoString:java/lang/String,inputKey:java/lang/Object,inputQuery:java/lang/Object,inputValue:java/lang/Object,keyClass:java/lang/String,limit:int,locateEntryLocations:java/util/List,locateEntryResult:org/apache/geode/management/internal/cli/domain/DataCommandResult$KeyInfo,operat [...]
 org/apache/geode/management/internal/cli/domain/DataCommandResult$KeyInfo,false,host:java/lang/String,locations:java/util/ArrayList,memberId:java/lang/String,memberName:java/lang/String,pid:int
@@ -556,7 +557,7 @@ org/apache/geode/management/internal/cli/functions/RebalanceFunction,true,1
 org/apache/geode/management/internal/cli/functions/RegionAlterFunction,true,-4846425364943216425
 org/apache/geode/management/internal/cli/functions/RegionCreateFunction,true,8746830191680509335
 org/apache/geode/management/internal/cli/functions/RegionDestroyFunction,true,9172773671865750685
-org/apache/geode/management/internal/cli/functions/RegionFunctionArgs,true,2204943186081037301,asyncEventQueueIds:java/util/Set,cacheListeners:java/util/Set,cacheLoader:java/lang/String,cacheWriter:java/lang/String,cloningEnabled:java/lang/Boolean,compressor:java/lang/String,concurrencyChecksEnabled:java/lang/Boolean,concurrencyLevel:java/lang/Integer,diskStore:java/lang/String,diskSynchronous:java/lang/Boolean,enableAsyncConflation:java/lang/Boolean,enableSubscriptionConflation:java/lan [...]
+org/apache/geode/management/internal/cli/functions/RegionFunctionArgs,true,2204943186081037302,asyncEventQueueIds:java/util/Set,cacheListeners:java/util/Set,cacheLoader:org/apache/geode/management/internal/cli/domain/ClassName,cacheWriter:org/apache/geode/management/internal/cli/domain/ClassName,cloningEnabled:java/lang/Boolean,compressor:java/lang/String,concurrencyChecksEnabled:java/lang/Boolean,concurrencyLevel:java/lang/Integer,diskStore:java/lang/String,diskSynchronous:java/lang/Boo [...]
 org/apache/geode/management/internal/cli/functions/RegionFunctionArgs$EvictionAttrs,true,9015454906371076014,evictionAction:java/lang/String,maxEntryCount:java/lang/Integer,maxMemory:java/lang/Integer,objectSizer:java/lang/String
 org/apache/geode/management/internal/cli/functions/RegionFunctionArgs$ExpirationAttrs,true,1474255033398008062,timeAndAction:org/apache/geode/cache/ExpirationAttributes,type:org/apache/geode/management/internal/cli/functions/RegionFunctionArgs$ExpirationAttrs$ExpirationFor
 org/apache/geode/management/internal/cli/functions/RegionFunctionArgs$ExpirationAttrs$ExpirationFor,false
diff --git a/geode-core/src/test/java/org/apache/geode/codeAnalysis/AnalyzeSerializablesJUnitTest.java b/geode-core/src/test/java/org/apache/geode/codeAnalysis/AnalyzeSerializablesJUnitTest.java
index 93628a4..c72a1bf 100644
--- a/geode-core/src/test/java/org/apache/geode/codeAnalysis/AnalyzeSerializablesJUnitTest.java
+++ b/geode-core/src/test/java/org/apache/geode/codeAnalysis/AnalyzeSerializablesJUnitTest.java
@@ -425,14 +425,17 @@ public class AnalyzeSerializablesJUnitTest {
     System.out.println("java classpath is " + classpath);
 
     String[] entries = classpath.split(File.pathSeparator);
-    String buildDirName = getModuleName() + File.separatorChar + "build" + File.separatorChar
+    String gradleBuildDirName = getModuleName() + File.separatorChar + "build" + File.separatorChar
         + "classes" + File.separatorChar + "main";
+    String ideaBuildDirName = getModuleName() + File.separatorChar + "out" + File.separatorChar
+        + "production" + File.separatorChar + "classes";
     String buildDir = null;
 
-    for (int i = 0; i < entries.length && buildDir == null; i++) {
-      System.out.println("examining '" + entries[i] + "'");
-      if (entries[i].endsWith(buildDirName)) {
-        buildDir = entries[i];
+    for (String entry : entries) {
+      System.out.println("examining '" + entry + "'");
+      if (entry.endsWith(gradleBuildDirName) || entry.endsWith(ideaBuildDirName)) {
+        buildDir = entry;
+        break;
       }
     }
 
diff --git a/geode-core/src/test/java/org/apache/geode/management/internal/cli/GfshParserJUnitTest.java b/geode-core/src/test/java/org/apache/geode/management/internal/cli/GfshParserJUnitTest.java
index 53af36c..66268d3 100644
--- a/geode-core/src/test/java/org/apache/geode/management/internal/cli/GfshParserJUnitTest.java
+++ b/geode-core/src/test/java/org/apache/geode/management/internal/cli/GfshParserJUnitTest.java
@@ -85,6 +85,14 @@ public class GfshParserJUnitTest {
   }
 
   @Test
+  public void splitWithWhiteSpacesExceptQuoted() {
+    input = "create region --cache-writer=\"my.abc{'k1' : 'v   1', 'k2' : 'v2'}\"";
+    tokens = GfshParser.splitUserInput(input);
+    assertThat(tokens.size()).isEqualTo(4);
+    assertThat(tokens.get(3)).isEqualTo("\"my.abc{'k1' : 'v   1', 'k2' : 'v2'}\"");
+  }
+
+  @Test
   public void testSplitUserInputWithJNoQuotes() {
     input =
         "start server --name=server1  --J=-Dgemfire.start-dev-rest-api=true --J=-Dgemfire.http-service-port=8080";
@@ -145,4 +153,13 @@ public class GfshParserJUnitTest {
         .isEqualTo("command --option 'test value' --J \"-Dkey=value"
             + GfshParser.J_ARGUMENT_DELIMITER + "-Dkey2=value2\"");
   }
+
+  @Test
+  public void spaceOrEmptyStringIsParsedCorrectly() {
+    input = "alter region --name=/Person --cache-writer='' --cache-loader=' '";
+    tokens = GfshParser.splitUserInput(input);
+    assertThat(tokens.size()).isEqualTo(8);
+    assertThat(tokens.get(7)).isEqualTo("' '");
+    assertThat(tokens.get(5)).isEqualTo("''");
+  }
 }
diff --git a/geode-core/src/test/java/org/apache/geode/management/internal/cli/GfshParserParsingTest.java b/geode-core/src/test/java/org/apache/geode/management/internal/cli/GfshParserParsingTest.java
index de48b4a..2ee8722 100644
--- a/geode-core/src/test/java/org/apache/geode/management/internal/cli/GfshParserParsingTest.java
+++ b/geode-core/src/test/java/org/apache/geode/management/internal/cli/GfshParserParsingTest.java
@@ -291,16 +291,6 @@ public class GfshParserParsingTest {
   }
 
   @Test
-  public void testAlterRegion() throws Exception {
-    String command =
-        "alter region --name=/Person --cache-writer='' --cache-listener='' --cache-loader=''";
-    GfshParseResult result = parser.parse(command);
-    assertThat(result.getParamValueAsString("cache-writer")).isNotNull().isEmpty();
-    assertThat(result.getParamValueAsString("cache-listener")).isNotNull().isEmpty();
-    assertThat(result.getParamValueAsString("cache-loader")).isNotNull().isEmpty();
-  }
-
-  @Test
   public void testValueOfJsonWithoutOuterQuoteAndSpace() throws Exception {
     String command = "put --key=('name':'id') --value=456 --region=/test";
     GfshParseResult result = parser.parse(command);
diff --git a/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/AlterRegionCommandDUnitTest.java b/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/AlterRegionCommandDUnitTest.java
index 07d9f35..e52e1d5 100644
--- a/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/AlterRegionCommandDUnitTest.java
+++ b/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/AlterRegionCommandDUnitTest.java
@@ -12,260 +12,120 @@
  * or implied. See the License for the specific language governing permissions and limitations under
  * the License.
  */
+
 package org.apache.geode.management.internal.cli.commands;
 
-import static org.apache.geode.distributed.ConfigurationProperties.GROUPS;
-import static org.apache.geode.distributed.ConfigurationProperties.NAME;
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
 
 import java.io.File;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.OutputStream;
 import java.util.Arrays;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Properties;
-import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.stream.Collectors;
 
-import org.junit.Ignore;
+import org.junit.BeforeClass;
+import org.junit.ClassRule;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.experimental.categories.Category;
+import org.junit.rules.TemporaryFolder;
 
-import org.apache.geode.cache.Cache;
 import org.apache.geode.cache.RegionAttributes;
-import org.apache.geode.cache.RegionShortcut;
-import org.apache.geode.cache.asyncqueue.AsyncEvent;
-import org.apache.geode.cache.asyncqueue.AsyncEventListener;
-import org.apache.geode.cache.wan.GatewaySenderFactory;
-import org.apache.geode.management.cli.Result;
-import org.apache.geode.management.internal.cli.i18n.CliStrings;
-import org.apache.geode.management.internal.cli.result.CommandResult;
-import org.apache.geode.management.internal.cli.util.CommandStringBuilder;
 import org.apache.geode.test.compiler.ClassBuilder;
-import org.apache.geode.test.dunit.Host;
-import org.apache.geode.test.dunit.VM;
+import org.apache.geode.test.dunit.rules.ClusterStartupRule;
+import org.apache.geode.test.dunit.rules.MemberVM;
 import org.apache.geode.test.junit.categories.DistributedTest;
-import org.apache.geode.test.junit.categories.FlakyTest;
-
-@Category({DistributedTest.class, FlakyTest.class}) // GEODE-3018 GEODE-3530
-@SuppressWarnings("serial")
-public class AlterRegionCommandDUnitTest extends CliCommandTestBase {
+import org.apache.geode.test.junit.rules.GfshCommandRule;
+import org.apache.geode.test.junit.rules.VMProvider;
 
-  private final String alterRegionName = "testAlterRegionRegion";
-  private final String alterAsyncEventQueueId1 = "testAlterRegionQueue1";
-  private final String alterAsyncEventQueueId2 = "testAlterRegionQueue2";
-  private final String alterAsyncEventQueueId3 = "testAlterRegionQueue3";
-  private final String alterGatewaySenderId1 = "testAlterRegionSender1";
-  private final String alterGatewaySenderId2 = "testAlterRegionSender2";
-  private final String alterGatewaySenderId3 = "testAlterRegionSender3";
-  private VM alterVm1;
-  private String alterVm1Name;
-  private VM alterVm2;
-  private String alterVm2Name;
+@Category(DistributedTest.class)
+public class AlterRegionCommandDUnitTest {
 
-  private final List<String> filesToBeDeleted = new CopyOnWriteArrayList<>();
+  @ClassRule
+  public static ClusterStartupRule cluster = new ClusterStartupRule();
 
-  @Ignore("bug51924")
-  @Test
-  public void testAlterRegion() throws IOException {
-    setUpJmxManagerOnVm0ThenConnect(null);
+  @ClassRule
+  public static GfshCommandRule gfsh = new GfshCommandRule();
 
-    CommandResult cmdResult = executeCommand(CliStrings.LIST_REGION);
-    assertEquals(Result.Status.OK, cmdResult.getStatus());
-    assertTrue(commandResultToString(cmdResult).contains("No Regions Found"));
-
-    Host.getHost(0).getVM(0).invoke(() -> {
-      Cache cache = getCache();
-      cache.createRegionFactory(RegionShortcut.PARTITION).setStatisticsEnabled(true)
-          .create(alterRegionName);
-    });
+  @Rule
+  public TemporaryFolder temporaryFolder = new TemporaryFolder();
 
-    this.alterVm1 = Host.getHost(0).getVM(1);
-    this.alterVm1Name = "VM" + this.alterVm1.getId();
-    this.alterVm1.invoke(() -> {
-      Properties localProps = new Properties();
-      localProps.setProperty(NAME, alterVm1Name);
-      localProps.setProperty(GROUPS, "Group1");
-      getSystem(localProps);
-      Cache cache = getCache();
-
-      // Setup queues and gateway senders to be used by all tests
-      cache.createRegionFactory(RegionShortcut.PARTITION).setStatisticsEnabled(true)
-          .create(alterRegionName);
-      AsyncEventListener listener = new AsyncEventListener() {
-        @Override
-        public void close() {
-          // Nothing to do
-        }
-
-        @Override
-        public boolean processEvents(List<AsyncEvent> events) {
-          return true;
-        }
-      };
-      cache.createAsyncEventQueueFactory().create(alterAsyncEventQueueId1, listener);
-      cache.createAsyncEventQueueFactory().create(alterAsyncEventQueueId2, listener);
-      cache.createAsyncEventQueueFactory().create(alterAsyncEventQueueId3, listener);
-
-      GatewaySenderFactory gatewaySenderFactory = cache.createGatewaySenderFactory();
-      gatewaySenderFactory.setManualStart(true);
-      gatewaySenderFactory.create(alterGatewaySenderId1, 2);
-      gatewaySenderFactory.create(alterGatewaySenderId2, 3);
-      gatewaySenderFactory.create(alterGatewaySenderId3, 4);
-    });
+  private static MemberVM locator, server1, server2, server3;
 
-    this.alterVm2 = Host.getHost(0).getVM(2);
-    this.alterVm2Name = "VM" + this.alterVm2.getId();
-    this.alterVm2.invoke(() -> {
-      Properties localProps = new Properties();
-      localProps.setProperty(NAME, alterVm2Name);
-      localProps.setProperty(GROUPS, "Group1,Group2");
-      getSystem(localProps);
-      Cache cache = getCache();
+  @BeforeClass
+  public static void beforeClass() throws Exception {
+    locator = cluster.startLocatorVM(0);
+    server1 = cluster.startServerVM(1, "group1", locator.getPort());
+    server2 = cluster.startServerVM(2, locator.getPort());
+    server3 = cluster.startServerVM(3, locator.getPort());
 
-      cache.createRegionFactory(RegionShortcut.PARTITION).setStatisticsEnabled(true)
-          .create(alterRegionName);
-    });
-
-    deployJarFilesForRegionAlter();
-    regionAlterGroupTest();
-    regionAlterSetAllTest();
-    regionAlterNoChangeTest();
-    regionAlterSetDefaultsTest();
-    regionAlterManipulatePlugInsTest();
-
-    this.alterVm1.invoke(() -> getCache().getRegion(alterRegionName).destroyRegion());
+    gfsh.connectAndVerify(locator);
   }
 
   @Test
   public void testAlterRegionResetCacheListeners() throws IOException {
-    setUpJmxManagerOnVm0ThenConnect(null);
+    gfsh.executeAndAssertThat("list regions").statusIsSuccess().containsOutput("No Regions Found");
 
-    CommandResult cmdResult = executeCommand(CliStrings.LIST_REGION);
-    assertEquals(Result.Status.OK, cmdResult.getStatus());
-    assertTrue(commandResultToString(cmdResult).contains("No Regions Found"));
-
-    Host.getHost(0).getVM(0).invoke(() -> {
-      Cache cache = getCache();
-      cache.createRegionFactory(RegionShortcut.PARTITION).setStatisticsEnabled(true)
-          .create(alterRegionName);
-    });
-
-    this.alterVm1 = Host.getHost(0).getVM(1);
-    this.alterVm1Name = "VM" + this.alterVm1.getId();
-    this.alterVm1.invoke(() -> {
-      Properties localProps = new Properties();
-      localProps.setProperty(NAME, alterVm1Name);
-      localProps.setProperty(GROUPS, "Group1");
-      getSystem(localProps);
-      Cache cache = getCache();
-
-      // Setup queues and gateway senders to be used by all tests
-      cache.createRegionFactory(RegionShortcut.PARTITION).setStatisticsEnabled(true)
-          .create(alterRegionName);
-    });
-
-    this.alterVm2 = Host.getHost(0).getVM(2);
-    this.alterVm2Name = "VM" + this.alterVm2.getId();
-    this.alterVm2.invoke(() -> {
-      Properties localProps = new Properties();
-      localProps.setProperty(NAME, alterVm2Name);
-      localProps.setProperty(GROUPS, "Group1,Group2");
-      getSystem(localProps);
-      Cache cache = getCache();
-
-      cache.createRegionFactory(RegionShortcut.PARTITION).setStatisticsEnabled(true)
-          .create(alterRegionName);
-    });
+    gfsh.executeAndAssertThat("create region --name=regionA --type=PARTITION").statusIsSuccess();
 
     deployJarFilesForRegionAlter();
 
-    CommandStringBuilder commandStringBuilder = new CommandStringBuilder(CliStrings.ALTER_REGION);
-    commandStringBuilder.addOption(CliStrings.ALTER_REGION__REGION, "/" + this.alterRegionName);
-    commandStringBuilder.addOption(CliStrings.ALTER_REGION__CACHELISTENER,
-        "com.cadrdunit.RegionAlterCacheListenerA,com.cadrdunit.RegionAlterCacheListenerB,com.cadrdunit.RegionAlterCacheListenerC");
+    String listenerABC =
+        "com.cadrdunit.RegionAlterCacheListenerA,com.cadrdunit.RegionAlterCacheListenerB,com.cadrdunit.RegionAlterCacheListenerC";
+    gfsh.executeAndAssertThat("alter region --name=regionA --cache-listener=" + listenerABC)
+        .statusIsSuccess().tableHasRowCount("Member", 3);
 
-    cmdResult = executeCommand(commandStringBuilder.toString());
-    assertEquals(Result.Status.OK, cmdResult.getStatus());
-    String stringResult = commandResultToString(cmdResult);
-
-    assertEquals(5, countLinesInString(stringResult, false));
-    assertEquals(false, stringResult.contains("ERROR"));
-    assertTrue(stringContainsLine(stringResult,
-        this.alterVm1Name + ".*Region \"/" + this.alterRegionName + "\" altered.*"));
-    assertTrue(stringContainsLine(stringResult,
-        this.alterVm2Name + ".*Region \"/" + this.alterRegionName + "\" altered.*"));
-
-    this.alterVm1.invoke(() -> {
-      RegionAttributes attributes = getCache().getRegion(alterRegionName).getAttributes();
+    VMProvider.invokeInEveryMember(() -> {
+      RegionAttributes attributes =
+          ClusterStartupRule.getCache().getRegion("regionA").getAttributes();
       assertEquals(3, attributes.getCacheListeners().length);
 
       assertThat(Arrays.stream(attributes.getCacheListeners()).map(c -> c.getClass().getName())
           .collect(Collectors.toSet())).containsExactlyInAnyOrder(
               "com.cadrdunit.RegionAlterCacheListenerA", "com.cadrdunit.RegionAlterCacheListenerB",
               "com.cadrdunit.RegionAlterCacheListenerC");
-    });
+    }, server1, server2, server3);
 
-    // Add 1 back to each of the sets
-    commandStringBuilder = new CommandStringBuilder(CliStrings.ALTER_REGION);
-    commandStringBuilder.addOption(CliStrings.ALTER_REGION__REGION, "/" + this.alterRegionName);
-    commandStringBuilder.addOption(CliStrings.GROUP, "Group1");
-    commandStringBuilder.addOption(CliStrings.ALTER_REGION__CACHELISTENER, "''");
-    cmdResult = executeCommand(commandStringBuilder.toString());
-    assertEquals(Result.Status.OK, cmdResult.getStatus());
-    stringResult = commandResultToString(cmdResult);
-    assertEquals(4, countLinesInString(stringResult, false));
-    assertEquals(false, stringResult.contains("ERROR"));
-    assertTrue(stringContainsLine(stringResult,
-        this.alterVm1Name + ".*Region \"/" + this.alterRegionName + "\" altered.*"));
-    assertTrue(stringContainsLine(stringResult,
-        this.alterVm2Name + ".*Region \"/" + this.alterRegionName + "\" altered.*"));
+    // remove listener on server1
+    gfsh.executeAndAssertThat("alter region --group=group1 --name=regionA --cache-listener=''")
+        .statusIsSuccess().tableHasRowCount("Member", 1).tableHasRowWithValues("Member", "Status",
+            "server-1", "Region \"/regionA\" altered on \"server-1\"");
 
-    this.alterVm1.invoke(() -> {
-      RegionAttributes attributes = getCache().getRegion(alterRegionName).getAttributes();
+    server1.invoke(() -> {
+      RegionAttributes attributes =
+          ClusterStartupRule.getCache().getRegion("regionA").getAttributes();
       assertEquals(0, attributes.getCacheListeners().length);
     });
   }
 
   private void deployJarFilesForRegionAlter() throws IOException {
     ClassBuilder classBuilder = new ClassBuilder();
-    final File jarFile1 = new File(new File(".").getAbsolutePath(), "testAlterRegion1.jar");
-    this.filesToBeDeleted.add(jarFile1.getAbsolutePath());
-    final File jarFile2 = new File(new File(".").getAbsolutePath(), "testAlterRegion2.jar");
-    this.filesToBeDeleted.add(jarFile2.getAbsolutePath());
-    final File jarFile3 = new File(new File(".").getAbsolutePath(), "testAlterRegion3.jar");
-    this.filesToBeDeleted.add(jarFile3.getAbsolutePath());
-    final File jarFile4 = new File(new File(".").getAbsolutePath(), "testAlterRegion4.jar");
-    this.filesToBeDeleted.add(jarFile4.getAbsolutePath());
-    final File jarFile5 = new File(new File(".").getAbsolutePath(), "testAlterRegion5.jar");
-    this.filesToBeDeleted.add(jarFile5.getAbsolutePath());
+    final File jarFile1 = new File(temporaryFolder.getRoot(), "testAlterRegion1.jar");
+    final File jarFile2 = new File(temporaryFolder.getRoot(), "testAlterRegion2.jar");
+    final File jarFile3 = new File(temporaryFolder.getRoot(), "testAlterRegion3.jar");
+    final File jarFile4 = new File(temporaryFolder.getRoot(), "testAlterRegion4.jar");
+    final File jarFile5 = new File(temporaryFolder.getRoot(), "testAlterRegion5.jar");
 
     byte[] jarBytes =
         classBuilder.createJarFromClassContent("com/cadrdunit/RegionAlterCacheListenerA",
             "package com.cadrdunit;" + "import org.apache.geode.cache.util.CacheListenerAdapter;"
                 + "public class RegionAlterCacheListenerA extends CacheListenerAdapter {}");
     writeJarBytesToFile(jarFile1, jarBytes);
-    CommandResult cmdResult = executeCommand("deploy --jar=testAlterRegion1.jar");
-    assertEquals(Result.Status.OK, cmdResult.getStatus());
+    gfsh.executeAndAssertThat("deploy --jar=" + jarFile1.getAbsolutePath()).statusIsSuccess();
 
     jarBytes = classBuilder.createJarFromClassContent("com/cadrdunit/RegionAlterCacheListenerB",
         "package com.cadrdunit;" + "import org.apache.geode.cache.util.CacheListenerAdapter;"
             + "public class RegionAlterCacheListenerB extends CacheListenerAdapter {}");
     writeJarBytesToFile(jarFile2, jarBytes);
-    cmdResult = executeCommand("deploy --jar=testAlterRegion2.jar");
-    assertEquals(Result.Status.OK, cmdResult.getStatus());
+    gfsh.executeAndAssertThat("deploy --jar=" + jarFile2.getAbsolutePath()).statusIsSuccess();
 
     jarBytes = classBuilder.createJarFromClassContent("com/cadrdunit/RegionAlterCacheListenerC",
         "package com.cadrdunit;" + "import org.apache.geode.cache.util.CacheListenerAdapter;"
             + "public class RegionAlterCacheListenerC extends CacheListenerAdapter {}");
     writeJarBytesToFile(jarFile3, jarBytes);
-    cmdResult = executeCommand("deploy --jar=testAlterRegion3.jar");
-    assertEquals(Result.Status.OK, cmdResult.getStatus());
+    gfsh.executeAndAssertThat("deploy --jar=" + jarFile3.getAbsolutePath()).statusIsSuccess();
 
     jarBytes = classBuilder.createJarFromClassContent("com/cadrdunit/RegionAlterCacheLoader",
         "package com.cadrdunit;" + "import org.apache.geode.cache.CacheLoader;"
@@ -275,361 +135,13 @@ public class AlterRegionCommandDUnitTest extends CliCommandTestBase {
             + "public void close() {}"
             + "public Object load(LoaderHelper helper) throws CacheLoaderException {return null;}}");
     writeJarBytesToFile(jarFile4, jarBytes);
-    cmdResult = executeCommand("deploy --jar=testAlterRegion4.jar");
-    assertEquals(Result.Status.OK, cmdResult.getStatus());
+    gfsh.executeAndAssertThat("deploy --jar=" + jarFile4.getAbsolutePath()).statusIsSuccess();
 
     jarBytes = classBuilder.createJarFromClassContent("com/cadrdunit/RegionAlterCacheWriter",
         "package com.cadrdunit;" + "import org.apache.geode.cache.util.CacheWriterAdapter;"
             + "public class RegionAlterCacheWriter extends CacheWriterAdapter {}");
     writeJarBytesToFile(jarFile5, jarBytes);
-    cmdResult = executeCommand("deploy --jar=testAlterRegion5.jar");
-    assertEquals(Result.Status.OK, cmdResult.getStatus());
-  }
-
-  private void regionAlterGroupTest() {
-    CommandStringBuilder commandStringBuilder = new CommandStringBuilder(CliStrings.ALTER_REGION);
-    commandStringBuilder.addOption(CliStrings.ALTER_REGION__REGION, this.alterRegionName);
-    commandStringBuilder.addOption(CliStrings.GROUP, "Group1");
-    commandStringBuilder.addOption(CliStrings.ALTER_REGION__EVICTIONMAX, "5764");
-    CommandResult cmdResult = executeCommand(commandStringBuilder.toString());
-    assertEquals(Result.Status.OK, cmdResult.getStatus());
-    String stringResult = commandResultToString(cmdResult);
-    assertEquals(4, countLinesInString(stringResult, false));
-    assertEquals(false, stringResult.contains("ERROR"));
-    assertTrue(stringContainsLine(stringResult,
-        this.alterVm1Name + ".*Region \"/" + this.alterRegionName + "\" altered.*"));
-    assertTrue(stringContainsLine(stringResult,
-        this.alterVm2Name + ".*Region \"/" + this.alterRegionName + "\" altered.*"));
-
-    this.alterVm1.invoke(() -> {
-      RegionAttributes attributes = getCache().getRegion(alterRegionName).getAttributes();
-      assertEquals(5764, attributes.getEvictionAttributes().getMaximum());
-    });
-
-    this.alterVm2.invoke(() -> {
-      RegionAttributes attributes = getCache().getRegion(alterRegionName).getAttributes();
-      assertEquals(5764, attributes.getEvictionAttributes().getMaximum());
-    });
-
-    commandStringBuilder = new CommandStringBuilder(CliStrings.ALTER_REGION);
-    commandStringBuilder.addOption(CliStrings.ALTER_REGION__REGION, "/" + this.alterRegionName);
-    commandStringBuilder.addOption(CliStrings.GROUP, "Group2");
-    commandStringBuilder.addOption(CliStrings.ALTER_REGION__EVICTIONMAX, "6963");
-    cmdResult = executeCommand(commandStringBuilder.toString());
-    assertEquals(Result.Status.OK, cmdResult.getStatus());
-    stringResult = commandResultToString(cmdResult);
-    assertEquals(3, countLinesInString(stringResult, false));
-    assertEquals(false, stringResult.contains("ERROR"));
-    assertFalse(stringContainsLine(stringResult,
-        this.alterVm1Name + ".*Region \"/" + this.alterRegionName + "\" altered.*"));
-    assertTrue(stringContainsLine(stringResult,
-        this.alterVm2Name + ".*Region \"/" + this.alterRegionName + "\" altered.*"));
-
-    this.alterVm1.invoke(() -> {
-      RegionAttributes attributes = getCache().getRegion(alterRegionName).getAttributes();
-      assertEquals(5764, attributes.getEvictionAttributes().getMaximum());
-    });
-
-    this.alterVm2.invoke(() -> {
-      RegionAttributes attributes = getCache().getRegion(alterRegionName).getAttributes();
-      assertEquals(6963, attributes.getEvictionAttributes().getMaximum());
-    });
-  }
-
-  private void regionAlterSetAllTest() {
-    CommandStringBuilder commandStringBuilder = new CommandStringBuilder(CliStrings.ALTER_REGION);
-    commandStringBuilder.addOption(CliStrings.ALTER_REGION__REGION, "/" + this.alterRegionName);
-    commandStringBuilder.addOption(CliStrings.ALTER_REGION__EVICTIONMAX, "35464");
-    commandStringBuilder.addOption(CliStrings.ALTER_REGION__CLONINGENABLED, "true");
-    commandStringBuilder.addOption(CliStrings.ALTER_REGION__ASYNCEVENTQUEUEID,
-        this.alterAsyncEventQueueId1);
-    commandStringBuilder.addOption(CliStrings.ALTER_REGION__ENTRYEXPIRATIONIDLETIME, "3453");
-    commandStringBuilder.addOption(CliStrings.ALTER_REGION__ENTRYEXPIRATIONIDLETIMEACTION,
-        "DESTROY");
-    commandStringBuilder.addOption(CliStrings.ALTER_REGION__ENTRYEXPIRATIONTIMETOLIVE, "7563");
-    commandStringBuilder.addOption(CliStrings.ALTER_REGION__ENTRYEXPIRATIONTTLACTION, "DESTROY");
-    commandStringBuilder.addOption(CliStrings.ALTER_REGION__CACHELISTENER,
-        "com.cadrdunit.RegionAlterCacheListenerA");
-    commandStringBuilder.addOption(CliStrings.ALTER_REGION__CACHELOADER,
-        "com.cadrdunit.RegionAlterCacheLoader");
-    commandStringBuilder.addOption(CliStrings.ALTER_REGION__CACHEWRITER,
-        "com.cadrdunit.RegionAlterCacheWriter");
-    commandStringBuilder.addOption(CliStrings.ALTER_REGION__GATEWAYSENDERID,
-        this.alterGatewaySenderId1);
-    commandStringBuilder.addOption(CliStrings.ALTER_REGION__REGIONEXPIRATIONIDLETIME, "6234");
-    commandStringBuilder.addOption(CliStrings.ALTER_REGION__REGIONEXPIRATIONIDLETIMEACTION,
-        "DESTROY");
-    commandStringBuilder.addOption(CliStrings.ALTER_REGION__REGIONEXPIRATIONTTL, "4562");
-    commandStringBuilder.addOption(CliStrings.ALTER_REGION__REGIONEXPIRATIONTTLACTION, "DESTROY");
-
-    CommandResult cmdResult = executeCommand(commandStringBuilder.toString());
-    assertEquals(Result.Status.OK, cmdResult.getStatus());
-    String stringResult = commandResultToString(cmdResult);
-    assertEquals(5, countLinesInString(stringResult, false));
-    assertEquals(false, stringResult.contains("ERROR"));
-    assertTrue(stringContainsLine(stringResult,
-        "Manager.*Region \"/" + this.alterRegionName + "\" altered.*"));
-    assertTrue(stringContainsLine(stringResult,
-        this.alterVm1Name + ".*Region \"/" + this.alterRegionName + "\" altered.*"));
-    assertTrue(stringContainsLine(stringResult,
-        this.alterVm2Name + ".*Region \"/" + this.alterRegionName + "\" altered.*"));
-
-    this.alterVm1.invoke(() -> {
-      RegionAttributes attributes = getCache().getRegion(alterRegionName).getAttributes();
-      assertEquals(35464, attributes.getEvictionAttributes().getMaximum());
-      assertEquals(3453, attributes.getEntryIdleTimeout().getTimeout());
-      assertTrue(attributes.getEntryIdleTimeout().getAction().isDestroy());
-      assertEquals(7563, attributes.getEntryTimeToLive().getTimeout());
-      assertTrue(attributes.getEntryTimeToLive().getAction().isDestroy());
-      assertEquals(6234, attributes.getRegionIdleTimeout().getTimeout());
-      assertTrue(attributes.getRegionIdleTimeout().getAction().isDestroy());
-      assertEquals(4562, attributes.getRegionTimeToLive().getTimeout());
-      assertTrue(attributes.getRegionTimeToLive().getAction().isDestroy());
-      assertEquals(1, attributes.getAsyncEventQueueIds().size());
-      assertTrue(attributes.getAsyncEventQueueIds().contains(alterAsyncEventQueueId1));
-      assertEquals(1, attributes.getGatewaySenderIds().size());
-      assertTrue(attributes.getGatewaySenderIds().contains(alterGatewaySenderId1));
-      assertEquals(1, attributes.getCacheListeners().length);
-      assertEquals("com.cadrdunit.RegionAlterCacheListenerA",
-          attributes.getCacheListeners()[0].getClass().getName());
-      assertEquals("com.cadrdunit.RegionAlterCacheWriter",
-          attributes.getCacheWriter().getClass().getName());
-      assertEquals("com.cadrdunit.RegionAlterCacheLoader",
-          attributes.getCacheLoader().getClass().getName());
-    });
-  }
-
-  private void regionAlterNoChangeTest() {
-    CommandStringBuilder commandStringBuilder = new CommandStringBuilder(CliStrings.ALTER_REGION);
-    commandStringBuilder.addOption(CliStrings.ALTER_REGION__REGION, "/" + this.alterRegionName);
-    commandStringBuilder.addOption(CliStrings.GROUP, "Group1");
-    commandStringBuilder.addOption(CliStrings.ALTER_REGION__CLONINGENABLED, "true");
-
-    CommandResult cmdResult = executeCommand(commandStringBuilder.toString());
-    assertEquals(Result.Status.OK, cmdResult.getStatus());
-    String stringResult = commandResultToString(cmdResult);
-    assertEquals(4, countLinesInString(stringResult, false));
-    assertEquals(false, stringResult.contains("ERROR"));
-    assertTrue(stringContainsLine(stringResult,
-        this.alterVm1Name + ".*Region \"/" + this.alterRegionName + "\" altered.*"));
-    assertTrue(stringContainsLine(stringResult,
-        this.alterVm2Name + ".*Region \"/" + this.alterRegionName + "\" altered.*"));
-
-    this.alterVm2.invoke(() -> {
-      RegionAttributes attributes = getCache().getRegion(alterRegionName).getAttributes();
-      assertEquals(35464, attributes.getEvictionAttributes().getMaximum());
-      assertEquals(3453, attributes.getEntryIdleTimeout().getTimeout());
-      assertTrue(attributes.getEntryIdleTimeout().getAction().isDestroy());
-      assertEquals(7563, attributes.getEntryTimeToLive().getTimeout());
-      assertTrue(attributes.getEntryTimeToLive().getAction().isDestroy());
-      assertEquals(6234, attributes.getRegionIdleTimeout().getTimeout());
-      assertTrue(attributes.getRegionIdleTimeout().getAction().isDestroy());
-      assertEquals(4562, attributes.getRegionTimeToLive().getTimeout());
-      assertTrue(attributes.getRegionTimeToLive().getAction().isDestroy());
-      assertEquals(1, attributes.getAsyncEventQueueIds().size());
-      assertTrue(attributes.getAsyncEventQueueIds().contains(alterAsyncEventQueueId1));
-      assertEquals(1, attributes.getGatewaySenderIds().size());
-      assertTrue(attributes.getGatewaySenderIds().contains(alterGatewaySenderId1));
-      assertEquals(1, attributes.getCacheListeners().length);
-      assertEquals("com.cadrdunit.RegionAlterCacheListenerA",
-          attributes.getCacheListeners()[0].getClass().getName());
-      assertEquals("com.cadrdunit.RegionAlterCacheWriter",
-          attributes.getCacheWriter().getClass().getName());
-      assertEquals("com.cadrdunit.RegionAlterCacheLoader",
-          attributes.getCacheLoader().getClass().getName());
-    });
-  }
-
-  private void regionAlterSetDefaultsTest() {
-    CommandStringBuilder commandStringBuilder = new CommandStringBuilder(CliStrings.ALTER_REGION);
-    commandStringBuilder.addOption(CliStrings.ALTER_REGION__REGION, "/" + this.alterRegionName);
-    commandStringBuilder.addOption(CliStrings.GROUP, "Group1");
-    commandStringBuilder.addOption(CliStrings.ALTER_REGION__EVICTIONMAX);
-    commandStringBuilder.addOption(CliStrings.ALTER_REGION__CLONINGENABLED);
-    commandStringBuilder.addOption(CliStrings.ALTER_REGION__ASYNCEVENTQUEUEID);
-    commandStringBuilder.addOption(CliStrings.ALTER_REGION__ENTRYEXPIRATIONIDLETIME);
-    commandStringBuilder.addOption(CliStrings.ALTER_REGION__ENTRYEXPIRATIONTTLACTION);
-    commandStringBuilder.addOption(CliStrings.ALTER_REGION__CACHELISTENER);
-    commandStringBuilder.addOption(CliStrings.ALTER_REGION__CACHELOADER);
-    commandStringBuilder.addOption(CliStrings.ALTER_REGION__CACHEWRITER);
-    commandStringBuilder.addOption(CliStrings.ALTER_REGION__GATEWAYSENDERID);
-    commandStringBuilder.addOption(CliStrings.ALTER_REGION__REGIONEXPIRATIONIDLETIME);
-    commandStringBuilder.addOption(CliStrings.ALTER_REGION__REGIONEXPIRATIONIDLETIMEACTION);
-
-    CommandResult cmdResult = executeCommand(commandStringBuilder.toString());
-    String stringResult = commandResultToString(cmdResult);
-    assertEquals(Result.Status.OK, cmdResult.getStatus());
-    assertEquals(4, countLinesInString(stringResult, false));
-    assertEquals(false, stringResult.contains("ERROR"));
-    assertTrue(stringContainsLine(stringResult,
-        this.alterVm1Name + ".*Region \"/" + this.alterRegionName + "\" altered.*"));
-    assertTrue(stringContainsLine(stringResult,
-        this.alterVm2Name + ".*Region \"/" + this.alterRegionName + "\" altered.*"));
-
-    this.alterVm1.invoke(() -> {
-      RegionAttributes attributes = getCache().getRegion(alterRegionName).getAttributes();
-      assertEquals(0, attributes.getEvictionAttributes().getMaximum());
-      assertEquals(0, attributes.getEntryIdleTimeout().getTimeout());
-      assertTrue(attributes.getEntryIdleTimeout().getAction().isDestroy());
-      assertEquals(7563, attributes.getEntryTimeToLive().getTimeout());
-      assertTrue(attributes.getEntryTimeToLive().getAction().isInvalidate());
-      assertEquals(0, attributes.getRegionIdleTimeout().getTimeout());
-      assertTrue(attributes.getRegionIdleTimeout().getAction().isInvalidate());
-      assertEquals(4562, attributes.getRegionTimeToLive().getTimeout());
-      assertTrue(attributes.getRegionTimeToLive().getAction().isDestroy());
-      assertEquals(0, attributes.getAsyncEventQueueIds().size());
-      assertEquals(0, attributes.getGatewaySenderIds().size());
-      assertEquals(0, attributes.getCacheListeners().length);
-    });
-  }
-
-  private void regionAlterManipulatePlugInsTest() {
-
-    // Start out by putting 3 entries into each of the plug-in sets
-    CommandStringBuilder commandStringBuilder = new CommandStringBuilder(CliStrings.ALTER_REGION);
-    commandStringBuilder.addOption(CliStrings.ALTER_REGION__REGION, "/" + this.alterRegionName);
-    commandStringBuilder.addOption(CliStrings.GROUP, "Group1");
-    commandStringBuilder.addOption(CliStrings.ALTER_REGION__ASYNCEVENTQUEUEID,
-        this.alterAsyncEventQueueId1);
-    commandStringBuilder.addOption(CliStrings.ALTER_REGION__ASYNCEVENTQUEUEID,
-        this.alterAsyncEventQueueId2);
-    commandStringBuilder.addOption(CliStrings.ALTER_REGION__ASYNCEVENTQUEUEID,
-        this.alterAsyncEventQueueId3);
-    commandStringBuilder.addOption(CliStrings.ALTER_REGION__GATEWAYSENDERID,
-        this.alterGatewaySenderId1);
-    commandStringBuilder.addOption(CliStrings.ALTER_REGION__GATEWAYSENDERID,
-        this.alterGatewaySenderId2);
-    commandStringBuilder.addOption(CliStrings.ALTER_REGION__GATEWAYSENDERID,
-        this.alterGatewaySenderId3);
-    commandStringBuilder.addOption(CliStrings.ALTER_REGION__CACHELISTENER,
-        "com.cadrdunit.RegionAlterCacheListenerA");
-    commandStringBuilder.addOption(CliStrings.ALTER_REGION__CACHELISTENER,
-        "com.cadrdunit.RegionAlterCacheListenerB");
-    commandStringBuilder.addOption(CliStrings.ALTER_REGION__CACHELISTENER,
-        "com.cadrdunit.RegionAlterCacheListenerC");
-    CommandResult cmdResult = executeCommand(commandStringBuilder.toString());
-    assertEquals(Result.Status.OK, cmdResult.getStatus());
-    String stringResult = commandResultToString(cmdResult);
-
-    assertEquals(4, countLinesInString(stringResult, false));
-    assertEquals(false, stringResult.contains("ERROR"));
-    assertTrue(stringContainsLine(stringResult,
-        this.alterVm1Name + ".*Region \"/" + this.alterRegionName + "\" altered.*"));
-    assertTrue(stringContainsLine(stringResult,
-        this.alterVm2Name + ".*Region \"/" + this.alterRegionName + "\" altered.*"));
-
-    this.alterVm1.invoke(() -> {
-      RegionAttributes attributes = getCache().getRegion(alterRegionName).getAttributes();
-      assertEquals(3, attributes.getAsyncEventQueueIds().size());
-      assertTrue(attributes.getAsyncEventQueueIds().contains(alterAsyncEventQueueId1));
-      assertTrue(attributes.getAsyncEventQueueIds().contains(alterAsyncEventQueueId2));
-      assertTrue(attributes.getAsyncEventQueueIds().contains(alterAsyncEventQueueId3));
-      assertEquals(3, attributes.getGatewaySenderIds().size());
-      assertTrue(attributes.getGatewaySenderIds().contains(alterGatewaySenderId1));
-      assertTrue(attributes.getGatewaySenderIds().contains(alterGatewaySenderId2));
-      assertTrue(attributes.getGatewaySenderIds().contains(alterGatewaySenderId3));
-      assertEquals(3, attributes.getCacheListeners().length);
-      assertEquals("com.cadrdunit.RegionAlterCacheListenerA",
-          attributes.getCacheListeners()[0].getClass().getName());
-      assertEquals("com.cadrdunit.RegionAlterCacheListenerB",
-          attributes.getCacheListeners()[1].getClass().getName());
-      assertEquals("com.cadrdunit.RegionAlterCacheListenerC",
-          attributes.getCacheListeners()[2].getClass().getName());
-    });
-
-    // Now take 1 entry out of each of the sets
-    commandStringBuilder = new CommandStringBuilder(CliStrings.ALTER_REGION);
-    commandStringBuilder.addOption(CliStrings.ALTER_REGION__REGION, "/" + this.alterRegionName);
-    commandStringBuilder.addOption(CliStrings.GROUP, "Group1");
-    commandStringBuilder.addOption(CliStrings.ALTER_REGION__ASYNCEVENTQUEUEID,
-        this.alterAsyncEventQueueId1);
-    commandStringBuilder.addOption(CliStrings.ALTER_REGION__ASYNCEVENTQUEUEID,
-        this.alterAsyncEventQueueId2);
-    commandStringBuilder.addOption(CliStrings.ALTER_REGION__GATEWAYSENDERID,
-        this.alterGatewaySenderId1);
-    commandStringBuilder.addOption(CliStrings.ALTER_REGION__GATEWAYSENDERID,
-        this.alterGatewaySenderId3);
-    commandStringBuilder.addOption(CliStrings.ALTER_REGION__CACHELISTENER,
-        "com.cadrdunit.RegionAlterCacheListenerB");
-    commandStringBuilder.addOption(CliStrings.ALTER_REGION__CACHELISTENER,
-        "com.cadrdunit.RegionAlterCacheListenerC");
-    cmdResult = executeCommand(commandStringBuilder.toString());
-    assertEquals(Result.Status.OK, cmdResult.getStatus());
-    stringResult = commandResultToString(cmdResult);
-    assertEquals(4, countLinesInString(stringResult, false));
-    assertEquals(false, stringResult.contains("ERROR"));
-    assertTrue(stringContainsLine(stringResult,
-        this.alterVm1Name + ".*Region \"/" + this.alterRegionName + "\" altered.*"));
-    assertTrue(stringContainsLine(stringResult,
-        this.alterVm2Name + ".*Region \"/" + this.alterRegionName + "\" altered.*"));
-
-    this.alterVm2.invoke(() -> {
-      RegionAttributes attributes = getCache().getRegion(alterRegionName).getAttributes();
-      assertEquals(2, attributes.getAsyncEventQueueIds().size());
-      Iterator iterator = attributes.getAsyncEventQueueIds().iterator();
-      assertEquals(alterAsyncEventQueueId1, iterator.next());
-      assertEquals(alterAsyncEventQueueId2, iterator.next());
-      assertEquals(2, attributes.getGatewaySenderIds().size());
-      iterator = attributes.getGatewaySenderIds().iterator();
-      assertEquals(alterGatewaySenderId1, iterator.next());
-      assertEquals(alterGatewaySenderId3, iterator.next());
-      assertEquals(2, attributes.getCacheListeners().length);
-      assertEquals("com.cadrdunit.RegionAlterCacheListenerB",
-          attributes.getCacheListeners()[0].getClass().getName());
-      assertEquals("com.cadrdunit.RegionAlterCacheListenerC",
-          attributes.getCacheListeners()[1].getClass().getName());
-    });
-
-    // Add 1 back to each of the sets
-    commandStringBuilder = new CommandStringBuilder(CliStrings.ALTER_REGION);
-    commandStringBuilder.addOption(CliStrings.ALTER_REGION__REGION, "/" + this.alterRegionName);
-    commandStringBuilder.addOption(CliStrings.GROUP, "Group1");
-    commandStringBuilder.addOption(CliStrings.ALTER_REGION__ASYNCEVENTQUEUEID,
-        this.alterAsyncEventQueueId1);
-    commandStringBuilder.addOption(CliStrings.ALTER_REGION__ASYNCEVENTQUEUEID,
-        this.alterAsyncEventQueueId2);
-    commandStringBuilder.addOption(CliStrings.ALTER_REGION__ASYNCEVENTQUEUEID,
-        this.alterAsyncEventQueueId3);
-    commandStringBuilder.addOption(CliStrings.ALTER_REGION__GATEWAYSENDERID,
-        this.alterGatewaySenderId1);
-    commandStringBuilder.addOption(CliStrings.ALTER_REGION__GATEWAYSENDERID,
-        this.alterGatewaySenderId3);
-    commandStringBuilder.addOption(CliStrings.ALTER_REGION__GATEWAYSENDERID,
-        this.alterGatewaySenderId2);
-    commandStringBuilder.addOption(CliStrings.ALTER_REGION__CACHELISTENER,
-        "com.cadrdunit.RegionAlterCacheListenerB");
-    commandStringBuilder.addOption(CliStrings.ALTER_REGION__CACHELISTENER,
-        "com.cadrdunit.RegionAlterCacheListenerC");
-    commandStringBuilder.addOption(CliStrings.ALTER_REGION__CACHELISTENER,
-        "com.cadrdunit.RegionAlterCacheListenerA");
-    cmdResult = executeCommand(commandStringBuilder.toString());
-    assertEquals(Result.Status.OK, cmdResult.getStatus());
-    stringResult = commandResultToString(cmdResult);
-    assertEquals(4, countLinesInString(stringResult, false));
-    assertEquals(false, stringResult.contains("ERROR"));
-    assertTrue(stringContainsLine(stringResult,
-        this.alterVm1Name + ".*Region \"/" + this.alterRegionName + "\" altered.*"));
-    assertTrue(stringContainsLine(stringResult,
-        this.alterVm2Name + ".*Region \"/" + this.alterRegionName + "\" altered.*"));
-
-    this.alterVm1.invoke(() -> {
-      RegionAttributes attributes = getCache().getRegion(alterRegionName).getAttributes();
-      assertEquals(3, attributes.getAsyncEventQueueIds().size());
-      assertTrue(attributes.getAsyncEventQueueIds().contains(alterAsyncEventQueueId1));
-      assertTrue(attributes.getAsyncEventQueueIds().contains(alterAsyncEventQueueId2));
-      assertTrue(attributes.getAsyncEventQueueIds().contains(alterAsyncEventQueueId3));
-      assertEquals(3, attributes.getGatewaySenderIds().size());
-      assertTrue(attributes.getGatewaySenderIds().contains(alterGatewaySenderId1));
-      assertTrue(attributes.getGatewaySenderIds().contains(alterGatewaySenderId3));
-      assertTrue(attributes.getGatewaySenderIds().contains(alterGatewaySenderId2));
-      assertEquals(3, attributes.getCacheListeners().length);
-      assertEquals("com.cadrdunit.RegionAlterCacheListenerB",
-          attributes.getCacheListeners()[0].getClass().getName());
-      assertEquals("com.cadrdunit.RegionAlterCacheListenerC",
-          attributes.getCacheListeners()[1].getClass().getName());
-      assertEquals("com.cadrdunit.RegionAlterCacheListenerA",
-          attributes.getCacheListeners()[2].getClass().getName());
-    });
+    gfsh.executeAndAssertThat("deploy --jar=" + jarFile5.getAbsolutePath()).statusIsSuccess();
   }
 
   private void writeJarBytesToFile(File jarFile, byte[] jarBytes) throws IOException {
diff --git a/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/AlterRegionCommandIntegrationTest.java b/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/AlterRegionCommandIntegrationTest.java
index 5ab4faf..1bd5429 100644
--- a/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/AlterRegionCommandIntegrationTest.java
+++ b/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/AlterRegionCommandIntegrationTest.java
@@ -48,19 +48,22 @@ public class AlterRegionCommandIntegrationTest {
   @Test
   public void invalidCacheListener() throws Exception {
     gfsh.executeAndAssertThat("alter region --name=/REPLICATED --cache-listener=abc-def")
-        .statusIsError().containsOutput("Specify a valid class name for cache-listener");
+        .statusIsError().containsOutput(
+            "java.lang.IllegalArgumentException: Failed to convert 'abc-def' to type ClassName[] for option 'cache-listener'");
   }
 
   @Test
   public void invalidCacheLoader() throws Exception {
     gfsh.executeAndAssertThat("alter region --name=/REPLICATED --cache-loader=abc-def")
-        .statusIsError().containsOutput("Specify a valid class name for cache-loader");
+        .statusIsError().containsOutput(
+            "java.lang.IllegalArgumentException: Failed to convert 'abc-def' to type ClassName for option 'cache-loader'");
   }
 
   @Test
   public void invalidCacheWriter() throws Exception {
     gfsh.executeAndAssertThat("alter region --name=/REPLICATED --cache-writer=abc-def")
-        .statusIsError().containsOutput("Specify a valid class name for cache-writer");
+        .statusIsError().containsOutput(
+            "java.lang.IllegalArgumentException: Failed to convert 'abc-def' to type ClassName for option 'cache-writer'");
   }
 
   @Test
diff --git a/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/AlterRegionCommandTest.java b/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/AlterRegionCommandTest.java
new file mode 100644
index 0000000..34a2ccf
--- /dev/null
+++ b/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/AlterRegionCommandTest.java
@@ -0,0 +1,66 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You 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 org.apache.geode.management.internal.cli.commands;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+import org.apache.geode.internal.cache.InternalCache;
+import org.apache.geode.management.internal.cli.GfshParseResult;
+import org.apache.geode.management.internal.cli.domain.ClassName;
+import org.apache.geode.test.junit.categories.UnitTest;
+import org.apache.geode.test.junit.rules.GfshParserRule;
+
+
+@Category(UnitTest.class)
+public class AlterRegionCommandTest {
+
+  @Rule
+  public GfshParserRule parser = new GfshParserRule();
+
+  private AlterRegionCommand command;
+  private InternalCache cache;
+
+  @Before
+  public void before() throws Exception {
+    command = spy(AlterRegionCommand.class);
+    cache = mock(InternalCache.class);
+    doReturn(cache).when(command).getCache();
+  }
+
+  @Test
+  public void cacheWriterEmpty() throws Exception {
+    String command = "alter region --name=/Person --cache-writer='' --cache-loader=' '";
+    GfshParseResult result = parser.parse(command);
+    assertThat(result.getParamValue("cache-writer")).isEqualTo(ClassName.EMPTY);
+    assertThat(result.getParamValue("cache-listener")).isNull();
+    assertThat(result.getParamValue("cache-loader")).isEqualTo(ClassName.EMPTY);
+  }
+
+  @Test
+  public void cacheWriterInvalid() throws Exception {
+    String command = "alter region --name=/Person --cache-writer='1abc'";
+    GfshParseResult result = parser.parse(command);
+    assertThat(result).isNull();
+  }
+}
diff --git a/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/CreateRegionCommandIntegrationTest.java b/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/CreateRegionCommandIntegrationTest.java
index 210b7ee..9b8bf91 100644
--- a/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/CreateRegionCommandIntegrationTest.java
+++ b/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/CreateRegionCommandIntegrationTest.java
@@ -180,19 +180,22 @@ public class CreateRegionCommandIntegrationTest {
   @Test
   public void invalidCacheListener() throws Exception {
     gfsh.executeAndAssertThat("create region --name=/FOO --type=REPLICATE --cache-listener=abc-def")
-        .statusIsError().containsOutput("Specify a valid class name for cache-listener");
+        .statusIsError().containsOutput(
+            "java.lang.IllegalArgumentException: Failed to convert 'abc-def' to type ClassName");
   }
 
   @Test
   public void invalidCacheLoader() throws Exception {
     gfsh.executeAndAssertThat("create region --name=/FOO --type=REPLICATE --cache-loader=abc-def")
-        .statusIsError().containsOutput("Specify a valid class name for cache-loader");
+        .statusIsError().containsOutput(
+            "java.lang.IllegalArgumentException: Failed to convert 'abc-def' to type ClassName");
   }
 
   @Test
   public void invalidCacheWriter() throws Exception {
     gfsh.executeAndAssertThat("create region --name=/FOO --type=REPLICATE --cache-writer=abc-def")
-        .statusIsError().containsOutput("Specify a valid class name for cache-writer");
+        .statusIsError().containsOutput(
+            "java.lang.IllegalArgumentException: Failed to convert 'abc-def' to type ClassName");
   }
 
   @Test
@@ -602,4 +605,10 @@ public class CreateRegionCommandIntegrationTest {
         .statusIsError().containsOutput(
             "eviction-object-sizer must implement both ObjectSizer and Declarable interfaces");
   }
+
+  @Test
+  public void createRegionWithCacheListenerWithInvalidJson() {
+    gfsh.executeAndAssertThat("create region --name=FOO --type=REPLICATE --cache-listener=abc{abc}")
+        .statusIsError().containsOutput("Invalid JSON: {abc}");
+  }
 }
diff --git a/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/CreateRegionCommandTest.java b/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/CreateRegionCommandTest.java
index e937673..8ce7ce9 100644
--- a/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/CreateRegionCommandTest.java
+++ b/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/CreateRegionCommandTest.java
@@ -39,6 +39,8 @@ import org.apache.geode.distributed.DistributedMember;
 import org.apache.geode.internal.cache.InternalCache;
 import org.apache.geode.management.DistributedSystemMXBean;
 import org.apache.geode.management.cli.Result;
+import org.apache.geode.management.internal.cli.GfshParseResult;
+import org.apache.geode.management.internal.cli.domain.ClassName;
 import org.apache.geode.management.internal.cli.functions.RegionFunctionArgs;
 import org.apache.geode.management.internal.cli.result.CommandResult;
 import org.apache.geode.test.junit.categories.UnitTest;
@@ -189,29 +191,124 @@ public class CreateRegionCommandTest {
 
   @Test
   public void invalidCacheListener() throws Exception {
-    CommandResult result = parser.executeCommandWithInstance(command,
-        "create region --name=region --type=REPLICATE --cache-listener=abc-def");
-    assertThat(result.getStatus()).isEqualTo(Result.Status.ERROR);
-    assertThat(result.getContent().toString())
-        .contains("Specify a valid class name for cache-listener.");
+    parser
+        .executeAndAssertThat(command,
+            "create region --name=region --type=REPLICATE --cache-listener=abc-def")
+        .statusIsError().containsOutput("Invalid command");
   }
 
   @Test
   public void invalidCacheLoader() throws Exception {
-    CommandResult result = parser.executeCommandWithInstance(command,
-        "create region --name=region --type=REPLICATE --cache-loader=abc-def");
-    assertThat(result.getStatus()).isEqualTo(Result.Status.ERROR);
-    assertThat(result.getContent().toString())
-        .contains("Specify a valid class name for cache-loader.");
+    parser
+        .executeAndAssertThat(command,
+            "create region --name=region --type=REPLICATE --cache-loader=abc-def")
+        .statusIsError().containsOutput("Invalid command");
   }
 
   @Test
   public void invalidCacheWriter() throws Exception {
-    CommandResult result = parser.executeCommandWithInstance(command,
-        "create region --name=region --type=REPLICATE --cache-writer=abc-def");
-    assertThat(result.getStatus()).isEqualTo(Result.Status.ERROR);
-    assertThat(result.getContent().toString())
-        .contains("Specify a valid class name for cache-writer.");
+    parser
+        .executeAndAssertThat(command,
+            "create region --name=region --type=REPLICATE --cache-writer=abc-def")
+        .statusIsError().containsOutput("Invalid command");
+  }
+
+  @Test
+  public void declarableClassIsNullIfNotSpecified() throws Exception {
+    GfshParseResult result = parser.parse("create region --name=region --cache-writer");
+    assertThat(result.getParamValue("cache-writer")).isNull();
+    assertThat(result.getParamValue("cache-loader")).isNull();
+    assertThat(result.getParamValue("cache-listener")).isNull();
+  }
+
+  @Test
+  // this is enforced by the parser, if empty string is passed, parser will turn that into null
+  // first
+  public void declarableClassIsNullWhenEmptyStringIsPassed() {
+    GfshParseResult result = parser
+        .parse("create region --name=region --cache-writer='' --cache-loader --cache-listener=''");
+    assertThat(result.getParamValue("cache-writer")).isNull();
+    assertThat(result.getParamValue("cache-loader")).isNull();
+    assertThat(result.getParamValue("cache-listener")).isNull();
+  }
+
+  @Test
+  public void emptySpace() {
+    GfshParseResult result = parser
+        .parse("create region --name=region --cache-writer=' ' --cache-loader --cache-listener=''");
+    assertThat(result.getParamValue("cache-writer")).isEqualTo(ClassName.EMPTY);
+    assertThat(result.getParamValue("cache-listener")).isNull();
+    assertThat(result.getParamValue("cache-loader")).isNull();
+  }
+
+  @Test
+  public void parseDeclarableWithClassOnly() {
+    GfshParseResult result = parser.parse("create region --name=region --cache-writer=my.abc");
+    ClassName writer = (ClassName) result.getParamValue("cache-writer");
+    assertThat(writer.getClassName()).isEqualTo("my.abc");
+    assertThat(writer.getInitProperties()).isNotNull().isEmpty();
+  }
+
+  @Test
+  public void parseDeclarableWithClassAndProps() {
+    String json = "{'k1':'v1','k2':'v2'}";
+    GfshParseResult result =
+        parser.parse("create region --name=region --cache-writer=my.abc" + json);
+    ClassName writer = (ClassName) result.getParamValue("cache-writer");
+    assertThat(writer.getClassName()).isEqualTo("my.abc");
+    assertThat(writer.getInitProperties()).containsKeys("k1", "k2");
+  }
+
+  @Test
+  public void parseDeclarableWithJsonWithSpace() {
+    String json = "{'k1' : 'v   1', 'k2' : 'v2'}";
+    GfshParseResult result =
+        parser.parse("create region --name=region --cache-writer=\"my.abc" + json + "\"");
+    ClassName writer = (ClassName) result.getParamValue("cache-writer");
+    assertThat(writer.getClassName()).isEqualTo("my.abc");
+    assertThat(writer.getInitProperties()).containsOnlyKeys("k1", "k2").containsEntry("k1",
+        "v   1");
+  }
+
+  @Test
+  public void cacheListenerClassOnly() {
+    GfshParseResult result =
+        parser.parse("create region --name=region --cache-listener=my.abc,my.def");
+    ClassName[] listeners = (ClassName[]) result.getParamValue("cache-listener");
+    assertThat(listeners).hasSize(2).contains(new ClassName("my.abc"), new ClassName("my.def"));
+  }
+
+  @Test
+  public void cacheListenerClassAndProps() {
+    String json1 = "{'k1':'v1'}";
+    String json2 = "{'k2':'v2'}";
+    GfshParseResult result = parser
+        .parse("create region --name=region --cache-listener=my.abc" + json1 + ",my.def" + json2);
+    ClassName[] listeners = (ClassName[]) result.getParamValue("cache-listener");
+    assertThat(listeners).hasSize(2).contains(new ClassName("my.abc", json1),
+        new ClassName("my.def", json2));
+  }
+
+  @Test
+  public void cacheListenerClassAndJsonWithComma() {
+    String json1 = "{'k1':'v1','k2':'v2'}";
+    String json2 = "{'k2':'v2'}";
+    GfshParseResult result = parser
+        .parse("create region --name=region --cache-listener=my.abc" + json1 + ",my.def" + json2);
+    ClassName[] listeners = (ClassName[]) result.getParamValue("cache-listener");
+    assertThat(listeners).hasSize(2).contains(new ClassName("my.abc", json1),
+        new ClassName("my.def", json2));
+  }
+
+  @Test
+  public void cacheListenerClassAndJsonWithCommaAndSpace() {
+    String json1 = "{'k1' : 'v1', 'k2' : 'v2'}";
+    String json2 = "{'k2' : 'v2'}";
+    GfshParseResult result = parser.parse(
+        "create region --name=region --cache-listener=\"my.abc" + json1 + ",my.def" + json2 + "\"");
+    ClassName[] listeners = (ClassName[]) result.getParamValue("cache-listener");
+    assertThat(listeners).hasSize(2).contains(new ClassName("my.abc", json1),
+        new ClassName("my.def", json2));
   }
 
   @Test
diff --git a/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/ShutdownCommandDUnitTest.java b/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/ShutdownCommandDUnitTest.java
index e463702..474a68c 100644
--- a/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/ShutdownCommandDUnitTest.java
+++ b/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/ShutdownCommandDUnitTest.java
@@ -14,12 +14,8 @@
  */
 package org.apache.geode.management.internal.cli.commands;
 
-import static org.apache.geode.distributed.ConfigurationProperties.GROUPS;
-import static org.apache.geode.distributed.ConfigurationProperties.LOG_FILE;
-import static org.apache.geode.distributed.ConfigurationProperties.NAME;
 import static org.assertj.core.api.Assertions.assertThat;
 
-import java.util.Properties;
 import java.util.concurrent.Callable;
 import java.util.concurrent.TimeUnit;
 
@@ -41,14 +37,8 @@ import org.apache.geode.test.junit.rules.GfshCommandRule;
 
 @Category(DistributedTest.class)
 public class ShutdownCommandDUnitTest {
-  private static final String MANAGER_NAME = "Manager";
-  private static final String SERVER1_NAME = "Server1";
-  private static final String SERVER2_NAME = "Server2";
-  private static final String GROUP0 = "Group0";
-  private static final String GROUP1 = "Group1";
-  private static final String GROUP2 = "Group2";
-
-  private MemberVM manager;
+
+  private MemberVM locator;
   private MemberVM server1;
   private MemberVM server2;
 
@@ -61,52 +51,34 @@ public class ShutdownCommandDUnitTest {
 
   @Before
   public void setup() throws Exception {
-    Properties managerProps = new Properties();
-    managerProps.setProperty(NAME, MANAGER_NAME);
-    managerProps.setProperty(GROUPS, GROUP0);
-    managerProps.setProperty(LOG_FILE, "someLog.log");
-
-    manager = clusterStartupRule.startLocatorVM(0, managerProps);
-
-    Properties server1Props = new Properties();
-    server1Props.setProperty(NAME, SERVER1_NAME);
-    server1Props.setProperty(GROUPS, GROUP1);
-    server1 = clusterStartupRule.startServerVM(1, server1Props, manager.getPort());
-
-    Properties server2Props = new Properties();
-    server2Props.setProperty(NAME, SERVER2_NAME);
-    server2Props.setProperty(GROUPS, GROUP2);
-    server2 = clusterStartupRule.startServerVM(2, server2Props, manager.getPort());
-
-    connect(manager);
+    locator = clusterStartupRule.startLocatorVM(0);
+    server1 = clusterStartupRule.startServerVM(1, locator.getPort());
+    server2 = clusterStartupRule.startServerVM(2, locator.getPort());
+    connect(locator);
   }
 
-  void connect(MemberVM server) throws Exception {
-    gfsh.connectAndVerify(server.getJmxPort(), GfshCommandRule.PortType.jmxManager);
+  void connect(MemberVM locator) throws Exception {
+    gfsh.connectAndVerify(locator);
   }
 
   @Test
   public void testShutdownServers() {
     String command = "shutdown";
 
-    gfsh.executeAndAssertThat(command).statusIsSuccess();
-    assertThat(gfsh.getGfshOutput()).contains("Shutdown is triggered");
-
+    gfsh.executeAndAssertThat(command).statusIsSuccess().containsOutput("Shutdown is triggered");
     verifyShutDown(server1, server2);
 
     // Make sure the locator is still running
     gfsh.executeAndAssertThat("list members").statusIsSuccess();
-    assertThat(gfsh.getGfshOutput()).contains(MANAGER_NAME);
+    assertThat(gfsh.getGfshOutput()).contains("locator-0");
   }
 
   @Test
   public void testShutdownAll() {
     String command = "shutdown --include-locators=true";
 
-    gfsh.executeAndAssertThat(command).statusIsSuccess();
-    assertThat(gfsh.getGfshOutput()).contains("Shutdown is triggered");
-
-    verifyShutDown(server1, server2, manager);
+    gfsh.executeAndAssertThat(command).statusIsSuccess().containsOutput("Shutdown is triggered");
+    verifyShutDown(server1, server2, locator);
   }
 
   private void verifyShutDown(MemberVM... members) {
diff --git a/geode-core/src/test/java/org/apache/geode/management/internal/cli/converters/ClassNameConverterTest.java b/geode-core/src/test/java/org/apache/geode/management/internal/cli/converters/ClassNameConverterTest.java
new file mode 100644
index 0000000..fb6eba5
--- /dev/null
+++ b/geode-core/src/test/java/org/apache/geode/management/internal/cli/converters/ClassNameConverterTest.java
@@ -0,0 +1,87 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You 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 org.apache.geode.management.internal.cli.converters;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+import org.apache.geode.management.internal.cli.domain.ClassName;
+import org.apache.geode.test.junit.categories.UnitTest;
+
+
+@Category(UnitTest.class)
+public class ClassNameConverterTest {
+
+  private ClassNameConverter converter;
+
+  @Before
+  public void before() throws Exception {
+    converter = new ClassNameConverter();
+  }
+
+  @Test
+  public void convertClassOnly() {
+    ClassName declarable = converter.convertFromText("abc", ClassName.class, "");
+    assertThat(declarable.getClassName()).isEqualTo("abc");
+    assertThat(declarable.getInitProperties()).isEmpty();
+  }
+
+  @Test
+  public void convertClassAndEmptyProp() {
+    ClassName declarable = converter.convertFromText("abc{}", ClassName.class, "");
+    assertThat(declarable.getClassName()).isEqualTo("abc");
+    assertThat(declarable.getInitProperties()).isEmpty();
+  }
+
+  @Test
+  public void convertWithOnlyDelimiter() {
+    assertThat(converter.convertFromText("{", ClassName.class, "")).isEqualTo(ClassName.EMPTY);
+  }
+
+  @Test
+  public void convertWithInvalidClassName() {
+    assertThatThrownBy(() -> converter.convertFromText("abc?{}", ClassName.class, ""))
+        .isInstanceOf(IllegalArgumentException.class).hasMessageContaining("Invalid className");
+  }
+
+  @Test
+  public void convertWithEmptyString() {
+    ClassName className = converter.convertFromText("", ClassName.class, "");
+    assertThat(className).isEqualTo(ClassName.EMPTY);
+  }
+
+  @Test
+  public void convertClassAndProperties() {
+    String json = "{'k1':'v1','k2':'v2'}";
+    ClassName declarable = converter.convertFromText("abc" + json, ClassName.class, "");
+    assertThat(declarable.getClassName()).isEqualTo("abc");
+    assertThat(declarable.getInitProperties()).containsOnlyKeys("k1", "k2")
+        .containsEntry("k1", "v1").containsEntry("k2", "v2");
+  }
+
+  @Test
+  public void convertClassAndPropertiesWithDoubleQuotes() {
+    String json = "{\"k1\":\"v1\",\"k2\":\"v2\"}";
+    ClassName declarable = converter.convertFromText("abc" + json, ClassName.class, "");
+    assertThat(declarable.getClassName()).isEqualTo("abc");
+    assertThat(declarable.getInitProperties()).containsOnlyKeys("k1", "k2")
+        .containsEntry("k1", "v1").containsEntry("k2", "v2");
+  }
+}
diff --git a/geode-core/src/test/java/org/apache/geode/management/internal/cli/domain/ClassNameTest.java b/geode-core/src/test/java/org/apache/geode/management/internal/cli/domain/ClassNameTest.java
new file mode 100644
index 0000000..07ebae6
--- /dev/null
+++ b/geode-core/src/test/java/org/apache/geode/management/internal/cli/domain/ClassNameTest.java
@@ -0,0 +1,115 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You 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 org.apache.geode.management.internal.cli.domain;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+import java.util.Properties;
+
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+import org.apache.geode.test.junit.categories.UnitTest;
+
+
+@Category(UnitTest.class)
+public class ClassNameTest {
+
+  @Test
+  public void constructWithoutProps() {
+    ClassName klass = new ClassName("someClassName");
+    Properties emptyProps = klass.getInitProperties();
+    assertThat(klass.getClassName()).isEqualTo("someClassName");
+    assertThat(emptyProps).isEmpty();
+  }
+
+  @Test
+  public void empty() {
+    assertThat(new ClassName("", "{}")).isEqualTo(new ClassName(" ", "{\"k\":\"v\"}"))
+        .isEqualTo(ClassName.EMPTY);
+  }
+
+  @Test
+  public void emptyCanNotInstantiate() {
+    assertThatThrownBy(() -> ClassName.EMPTY.newInstance()).isInstanceOf(RuntimeException.class)
+        .hasMessageContaining("Error instantiating class");
+  }
+
+  @Test
+  public void constructWithProperties() {
+    ClassName klass = new ClassName("someClassName", "{\"key\" : \"value\"}");
+    Properties keyValueProps = klass.getInitProperties();
+    assertThat(klass.getClassName()).isEqualTo("someClassName");
+    assertThat(keyValueProps).containsOnlyKeys("key").containsEntry("key", "value");
+  }
+
+  @Test
+  public void constructWithPropertiesWithSpace() {
+    String json = "{'k1' : 'v   1', 'k2' : 'v2'}";
+    ClassName klass = new ClassName("someClassName", json);
+    Properties keyValueProps = klass.getInitProperties();
+    assertThat(klass.getClassName()).isEqualTo("someClassName");
+    assertThat(keyValueProps).containsOnlyKeys("k1", "k2").containsEntry("k1", "v   1");
+  }
+
+  @Test
+  public void constructWithSingleQuotes() {
+    ClassName klass = new ClassName("someClassName", "{'key' : 'value'}");
+    Properties keyValueProps = klass.getInitProperties();
+    assertThat(klass.getClassName()).isEqualTo("someClassName");
+    assertThat(keyValueProps).containsOnlyKeys("key").containsEntry("key", "value");
+  }
+
+  @Test
+  public void constructWithEscapedComma() {
+    ClassName klass = new ClassName("someClassName", "{'key':'value','key2':'value2'}");
+    Properties keyValueProps = klass.getInitProperties();
+    assertThat(klass.getClassName()).isEqualTo("someClassName");
+    assertThat(keyValueProps).containsOnlyKeys("key", "key2").containsEntry("key", "value");
+  }
+
+
+  @Test
+  public void emptyClassName() {
+    assertThat(new ClassName(null)).isEqualTo(ClassName.EMPTY);
+    assertThat(new ClassName("")).isEqualTo(ClassName.EMPTY);
+    assertThat(new ClassName(" ")).isEqualTo(ClassName.EMPTY);
+  }
+
+  @Test
+  public void illegalJson() {
+    assertThatThrownBy(() -> new ClassName("test", ""))
+        .isInstanceOf(IllegalArgumentException.class);
+    assertThatThrownBy(() -> new ClassName("test", "a:b"))
+        .isInstanceOf(IllegalArgumentException.class);
+  }
+
+  @Test
+  public void getInstance() {
+    ClassName<String> klass = new ClassName("java.lang.String");
+    String s = klass.newInstance();
+    assertThat(s.toString()).isEqualTo("");
+  }
+
+  @Test
+  public void getInstanceWithProps() {
+    String json = "{\"k\":\"v\"}";
+    ClassName<MyCacheWriter> cacheWriter = new ClassName<>(MyCacheWriter.class.getName(), json);
+    MyCacheWriter obj = cacheWriter.newInstance();
+    assertThat(obj.getProperties()).containsEntry("k", "v").containsOnlyKeys("k");
+  }
+}
diff --git a/geode-core/src/test/java/org/apache/geode/management/internal/cli/domain/MyCacheWriter.java b/geode-core/src/test/java/org/apache/geode/management/internal/cli/domain/MyCacheWriter.java
new file mode 100644
index 0000000..fe30a95
--- /dev/null
+++ b/geode-core/src/test/java/org/apache/geode/management/internal/cli/domain/MyCacheWriter.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You 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 org.apache.geode.management.internal.cli.domain;
+
+import java.util.Properties;
+
+import org.apache.geode.cache.util.CacheWriterAdapter;
+
+public class MyCacheWriter extends CacheWriterAdapter {
+  Properties properties;
+
+  public Properties getProperties() {
+    return properties;
+  }
+
+  @Override
+  public void init(Properties properties) {
+    this.properties = properties;
+  }
+}

-- 
To stop receiving notification emails like this one, please contact
jinmeiliao@apache.org.

Mime
View raw message