You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@geode.apache.org by ji...@apache.org on 2018/12/06 19:13:33 UTC

[geode] branch develop updated (dfaf11c -> 93ed36f)

This is an automated email from the ASF dual-hosted git repository.

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


    from dfaf11c  GEODE-6151: use same term for JDBC mapping (#2957)
     new e9f5cd3  GEODE-5971: Refactor CreateRegionCommand to extend SingleGfshCommand
     new 846af4e  GEODE-5971: RegionConfig can only have one RegionAttributesType
     new 93ed36f  GEODE-5971: create region still needs to fetch xml from server to get get extensions xml

The 3 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../cli/commands/ConfigureEvictionThroughGfsh.java |   6 +-
 .../integrationTest/resources/assembly_content.txt |   5 +
 .../cli/CreateMappingCommandDUnitTest.java         |   2 +-
 .../cli/DestroyMappingCommandDunitTest.java        |   2 +-
 .../jdbc/internal/cli/CreateMappingCommand.java    |  28 +-
 .../jdbc/internal/cli/DestroyMappingCommand.java   |  22 +-
 .../internal/cli/CreateMappingCommandTest.java     |  24 +-
 .../internal/cli/DestroyMappingCommandTest.java    |   4 +-
 geode-core/build.gradle                            |   1 -
 .../CreateDefinedIndexesCommandDUnitTest.java      |  13 +-
 .../cli/commands/CreateRegionCommandDUnitTest.java | 120 ++-
 ...egionCommandPersistsConfigurationDUnitTest.java | 821 +++++++++++++++++++++
 .../commands/DestroyRegionCommandDUnitTest.java    |   7 +-
 .../ImportOldClusterConfigDUnitTest.java           |   2 +-
 .../java/org/apache/geode/cache/DataPolicy.java    |   7 +
 .../org/apache/geode/cache/EvictionAttributes.java |  39 +
 .../org/apache/geode/cache/ExpirationAction.java   |  15 +
 .../apache/geode/cache/ExpirationAttributes.java   |  16 +-
 .../apache/geode/cache/PartitionAttributes.java    |  19 +
 .../main/java/org/apache/geode/cache/Scope.java    |   4 +
 .../cache/configuration/RegionAttributesType.java  |  11 +
 .../geode/cache/configuration/RegionConfig.java    |  45 +-
 .../InternalConfigurationPersistenceService.java   |  27 +-
 .../apache/geode/internal/config/JAXBService.java  |  26 +-
 .../internal/cli/commands/AlterRegionCommand.java  |   3 +-
 .../internal/cli/commands/CreateRegionCommand.java | 146 +++-
 .../internal/cli/domain/RegionConfigFactory.java   | 341 +++++++++
 .../cli/functions/RegionAlterFunction.java         |  12 +-
 .../cli/functions/RegionCreateFunction.java        | 178 +++--
 .../internal/cli/functions/RegionFunctionArgs.java |  86 ++-
 .../management/internal/cli/i18n/CliStrings.java   |   2 +
 .../management/internal/cli/util/RegionPath.java   |  16 +
 .../geode/redis/internal/RegionProvider.java       |  20 +-
 .../sanctioned-geode-core-serializables.txt        |   2 +-
 .../geode/cache/configuration/CacheConfigTest.java |  18 +
 .../geode/internal/config/JAXBServiceTest.java     |  22 +
 .../cli/commands/CreateRegionCommandTest.java      |  26 +-
 .../cli/domain/RegionConfigFactoryTest.java        | 255 +++++++
 .../cli/functions/RegionFunctionArgsTest.java      |  45 +-
 .../LuceneClusterConfigurationDUnitTest.java       |   4 +-
 .../cli/functions/LuceneCreateIndexFunction.java   |   4 +-
 .../lucene/management/configuration/Index.java     | 237 ++++++
 .../management/configuration/package-info.java     |  18 +-
 .../sanctioned-geode-lucene-serializables.txt      |   1 +
 .../cli/commands/CreateRegionCommandDUnitTest.java |  55 +-
 45 files changed, 2428 insertions(+), 329 deletions(-)
 create mode 100644 geode-core/src/distributedTest/java/org/apache/geode/management/internal/cli/commands/CreateRegionCommandPersistsConfigurationDUnitTest.java
 create mode 100644 geode-core/src/main/java/org/apache/geode/management/internal/cli/domain/RegionConfigFactory.java
 create mode 100644 geode-core/src/test/java/org/apache/geode/management/internal/cli/domain/RegionConfigFactoryTest.java
 create mode 100644 geode-lucene/src/main/java/org/apache/geode/cache/lucene/management/configuration/Index.java
 copy extensions/geode-modules-session-internal/src/main/java/org/apache/geode/modules/session/internal/jmx/SessionStatisticsMXBean.java => geode-lucene/src/main/java/org/apache/geode/cache/lucene/management/configuration/package-info.java (67%)


[geode] 03/03: GEODE-5971: create region still needs to fetch xml from server to get get extensions xml

Posted by ji...@apache.org.
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

commit 93ed36f9c9248261fdb7817da4e51f49849f876c
Author: Jinmei Liao <ji...@pivotal.io>
AuthorDate: Wed Dec 5 15:15:07 2018 -0800

    GEODE-5971: create region still needs to fetch xml from server to get get extensions xml
---
 .gitignore                                         |   1 -
 .../integrationTest/resources/assembly_content.txt |   7 +-
 .../InternalConfigurationPersistenceService.java   |   4 +
 .../apache/geode/internal/config/JAXBService.java  |  22 +-
 .../internal/cli/commands/CreateRegionCommand.java |  23 ++
 .../cli/functions/RegionCreateFunction.java        |  15 +-
 .../geode/internal/config/JAXBServiceTest.java     |  22 ++
 .../LuceneClusterConfigurationDUnitTest.java       |   4 +-
 .../cli/functions/LuceneCreateIndexFunction.java   |   4 +-
 .../lucene/management/configuration/Index.java     | 237 +++++++++++++++++++++
 .../management/configuration/package-info.java     |  22 ++
 .../sanctioned-geode-lucene-serializables.txt      |   1 +
 12 files changed, 346 insertions(+), 16 deletions(-)

diff --git a/.gitignore b/.gitignore
index 1525f4a..47d635b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -28,7 +28,6 @@ out/
 *.orig
 geode-pulse/screenshots/
 /jpf.properties
-geode-assembly/assembly_content.txt
 
 .git-together
 bin/
diff --git a/geode-assembly/src/integrationTest/resources/assembly_content.txt b/geode-assembly/src/integrationTest/resources/assembly_content.txt
index f216ab3..2844d1e 100644
--- a/geode-assembly/src/integrationTest/resources/assembly_content.txt
+++ b/geode-assembly/src/integrationTest/resources/assembly_content.txt
@@ -388,6 +388,11 @@ javadoc/org/apache/geode/cache/lucene/LuceneServiceProvider.html
 javadoc/org/apache/geode/cache/lucene/PageableLuceneQueryResults.html
 javadoc/org/apache/geode/cache/lucene/management/LuceneIndexMetrics.html
 javadoc/org/apache/geode/cache/lucene/management/LuceneServiceMXBean.html
+javadoc/org/apache/geode/cache/lucene/management/configuration/Index.Field.html
+javadoc/org/apache/geode/cache/lucene/management/configuration/Index.html
+javadoc/org/apache/geode/cache/lucene/management/configuration/package-frame.html
+javadoc/org/apache/geode/cache/lucene/management/configuration/package-summary.html
+javadoc/org/apache/geode/cache/lucene/management/configuration/package-tree.html
 javadoc/org/apache/geode/cache/lucene/management/package-frame.html
 javadoc/org/apache/geode/cache/lucene/management/package-summary.html
 javadoc/org/apache/geode/cache/lucene/management/package-tree.html
@@ -957,4 +962,4 @@ tools/Modules/Apache_Geode_Modules-0.0.0-AppServer.zip
 tools/Modules/Apache_Geode_Modules-0.0.0-Tomcat.zip
 tools/Modules/Apache_Geode_Modules-0.0.0-tcServer.zip
 tools/Modules/Apache_Geode_Modules-0.0.0-tcServer30.zip
-tools/Pulse/geode-pulse-0.0.0.war
\ No newline at end of file
+tools/Pulse/geode-pulse-0.0.0.war
diff --git a/geode-core/src/main/java/org/apache/geode/distributed/internal/InternalConfigurationPersistenceService.java b/geode-core/src/main/java/org/apache/geode/distributed/internal/InternalConfigurationPersistenceService.java
index c86a969..f9f1169 100644
--- a/geode-core/src/main/java/org/apache/geode/distributed/internal/InternalConfigurationPersistenceService.java
+++ b/geode-core/src/main/java/org/apache/geode/distributed/internal/InternalConfigurationPersistenceService.java
@@ -156,6 +156,10 @@ public class InternalConfigurationPersistenceService implements ConfigurationPer
     jaxbService = new JAXBService(CacheConfig.class);
   }
 
+  public JAXBService getJaxbService() {
+    return jaxbService;
+  }
+
   public InternalConfigurationPersistenceService(InternalCache cache, Class<?>... xsdClasses)
       throws IOException {
     this.cache = cache;
diff --git a/geode-core/src/main/java/org/apache/geode/internal/config/JAXBService.java b/geode-core/src/main/java/org/apache/geode/internal/config/JAXBService.java
index 221e154..3ceb644 100644
--- a/geode-core/src/main/java/org/apache/geode/internal/config/JAXBService.java
+++ b/geode-core/src/main/java/org/apache/geode/internal/config/JAXBService.java
@@ -44,6 +44,7 @@ import org.apache.geode.internal.ClassPathLoader;
 public class JAXBService {
   Marshaller marshaller;
   Unmarshaller unmarshaller;
+  NameSpaceFilter nameSpaceFilter;
 
   public JAXBService(Class<?>... xsdRootClasses) {
     try {
@@ -63,6 +64,10 @@ public class JAXBService {
       }).filter(Objects::nonNull).collect(Collectors.joining(" "));
 
       marshaller.setProperty(Marshaller.JAXB_SCHEMA_LOCATION, schemas);
+      // use a custom Filter so that we can unmarshall older namespace or no namespace xml
+      XMLReader reader = XMLReaderFactory.createXMLReader();
+      nameSpaceFilter = new NameSpaceFilter();
+      nameSpaceFilter.setParent(reader);
     } catch (Exception e) {
       throw new RuntimeException(e.getMessage(), e);
     }
@@ -99,19 +104,20 @@ public class JAXBService {
 
   public <T> T unMarshall(String xml) {
     try {
-      InputSource is = new InputSource(new StringReader(xml));
-      XMLReader reader = XMLReaderFactory.createXMLReader();
-
-      // use a custom Filter so that we can unmarshall older namespace or no namespace xml
-      NameSpaceFilter filter = new NameSpaceFilter();
-      filter.setParent(reader);
-      SAXSource source = new SAXSource(filter, is);
-
+      SAXSource source = new SAXSource(nameSpaceFilter, new InputSource(new StringReader(xml)));
       return (T) unmarshaller.unmarshal(source);
     } catch (Exception e) {
       throw new RuntimeException(e.getMessage(), e);
     }
   }
 
+  public <T> T unMarshall(String xml, Class<T> klass) {
+    try {
+      SAXSource source = new SAXSource(nameSpaceFilter, new InputSource(new StringReader(xml)));
+      return unmarshaller.unmarshal(source, klass).getValue();
+    } catch (Exception e) {
+      throw new RuntimeException(e.getMessage(), e);
+    }
+  }
 
 }
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 4686f01..888287d 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
@@ -40,9 +40,11 @@ import org.apache.geode.cache.Region;
 import org.apache.geode.cache.RegionAttributes;
 import org.apache.geode.cache.RegionShortcut;
 import org.apache.geode.cache.configuration.CacheConfig;
+import org.apache.geode.cache.configuration.CacheElement;
 import org.apache.geode.cache.configuration.RegionConfig;
 import org.apache.geode.cache.execute.ResultCollector;
 import org.apache.geode.distributed.DistributedMember;
+import org.apache.geode.distributed.internal.InternalConfigurationPersistenceService;
 import org.apache.geode.internal.cache.InternalCache;
 import org.apache.geode.internal.logging.LogService;
 import org.apache.geode.management.DistributedRegionMXBean;
@@ -442,9 +444,30 @@ public class CreateRegionCommand extends SingleGfshCommand {
         RegionCreateFunction.INSTANCE, functionArgs, membersToCreateRegionOn);
 
     ResultModel resultModel = ResultModel.createMemberStatusResult(regionCreateResults);
+    InternalConfigurationPersistenceService service =
+        (InternalConfigurationPersistenceService) getConfigurationPersistenceService();
+
+    if (service == null) {
+      return resultModel;
+    }
+
+    // otherwise, prepare the regionConfig for persistence
     if (resultModel.isSuccessful()) {
       verifyDistributedRegionMbean(cache, regionPath);
       RegionConfig config = (new RegionConfigFactory()).generate(functionArgs);
+      // the following is a temporary solution before lucene make the change to create region first
+      // before creating the lucene index.
+      // GEODE-3924
+      // we will need to get the xml returned from the server to find out any custom xml nested
+      // inside the region
+      String regionXml = (String) regionCreateResults.stream()
+          .filter(CliFunctionResult::isSuccessful)
+          .findFirst().get().getResultObject();
+      RegionConfig regionConfigFromServer =
+          service.getJaxbService().unMarshall(regionXml, RegionConfig.class);
+      List<CacheElement> extensions = regionConfigFromServer.getCustomRegionElements();
+      config.getCustomRegionElements().addAll(extensions);
+
       resultModel.setConfigObject(new CreateRegionResultConfig(config,
           functionArgs.getRegionPath()));
     }
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 9dfa16d..26ed5a4 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
@@ -44,12 +44,14 @@ import org.apache.geode.compression.Compressor;
 import org.apache.geode.internal.ClassPathLoader;
 import org.apache.geode.internal.cache.InternalCache;
 import org.apache.geode.internal.cache.execute.InternalFunction;
+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.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;
 
 /**
  *
@@ -93,9 +95,9 @@ public class RegionCreateFunction implements InternalFunction {
 
     try {
       Region<?, ?> createdRegion = createRegion(cache, regionCreateArgs);
-
+      XmlEntity xmlEntity = getXmlEntityForRegion(createdRegion);
       resultSender
-          .lastResult(new CliFunctionResult(memberNameOrId, CliFunctionResult.StatusState.OK,
+          .lastResult(new CliFunctionResult(memberNameOrId, xmlEntity.getXmlDefinition(),
               CliStrings.format(CliStrings.CREATE_REGION__MSG__REGION_0_CREATED_ON_1,
                   createdRegion.getFullPath(), memberNameOrId)));
     } catch (IllegalStateException e) {
@@ -124,6 +126,15 @@ public class RegionCreateFunction implements InternalFunction {
     }
   }
 
+  private XmlEntity getXmlEntityForRegion(Region<?, ?> region) {
+    Region<?, ?> curRegion = region;
+    while (curRegion != null && curRegion.getParentRegion() != null) {
+      curRegion = curRegion.getParentRegion();
+    }
+
+    return new XmlEntity(CacheXml.REGION, "name", curRegion.getName());
+  }
+
   private CliFunctionResult handleException(final String memberNameOrId, final String exceptionMsg,
       final Exception e) {
     if (e != null && logger.isDebugEnabled()) {
diff --git a/geode-core/src/test/java/org/apache/geode/internal/config/JAXBServiceTest.java b/geode-core/src/test/java/org/apache/geode/internal/config/JAXBServiceTest.java
index 67f0807..c39866a 100644
--- a/geode-core/src/test/java/org/apache/geode/internal/config/JAXBServiceTest.java
+++ b/geode-core/src/test/java/org/apache/geode/internal/config/JAXBServiceTest.java
@@ -137,6 +137,28 @@ public class JAXBServiceTest {
   }
 
   @Test
+  public void unmarshallPartialElement() {
+    String xml = "<region name=\"one\">\n"
+        + "        <region-attributes scope=\"distributed-ack\" data-policy=\"replicate\"/>\n"
+        + "    </region>";
+
+    RegionConfig config = service2.unMarshall(xml, RegionConfig.class);
+    assertThat(config.getName()).isEqualTo("one");
+  }
+
+  @Test
+  public void unmarshallAnyElement() {
+    String xml = "<region name=\"one\">\n"
+        + "        <region-attributes scope=\"distributed-ack\" data-policy=\"replicate\"/>\n"
+        + "        <custom:any xmlns:custom=\"http://geode.apache.org/schema/custom\" id=\"any\"/>"
+        + "    </region>";
+
+    RegionConfig config = service2.unMarshall(xml, RegionConfig.class);
+    assertThat(config.getName()).isEqualTo("one");
+    assertThat(config.getCustomRegionElements()).hasSize(1);
+  }
+
+  @Test
   public void unmarshallIgnoresUnknownProperties() {
     // say xml has a type attribute that is removed in the new version
     String existingXML = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n"
diff --git a/geode-lucene/src/distributedTest/java/org/apache/geode/cache/lucene/internal/configuration/LuceneClusterConfigurationDUnitTest.java b/geode-lucene/src/distributedTest/java/org/apache/geode/cache/lucene/internal/configuration/LuceneClusterConfigurationDUnitTest.java
index 98c7169..e05b15a 100644
--- a/geode-lucene/src/distributedTest/java/org/apache/geode/cache/lucene/internal/configuration/LuceneClusterConfigurationDUnitTest.java
+++ b/geode-lucene/src/distributedTest/java/org/apache/geode/cache/lucene/internal/configuration/LuceneClusterConfigurationDUnitTest.java
@@ -267,10 +267,10 @@ public class LuceneClusterConfigurationDUnitTest {
       Configuration config = sc.getConfiguration(ConfigurationPersistenceService.CLUSTER_CONFIG);
       String xmlContent = config.getCacheXmlContent();
       String luceneIndex0Config = "<" + LuceneXmlConstants.PREFIX + ":" + LuceneXmlConstants.INDEX
-          + " xmlns:lucene=\"" + LuceneXmlConstants.NAMESPACE + "\" " + LuceneXmlConstants.NAME
+          + " " + LuceneXmlConstants.NAME
           + "=\"" + INDEX_NAME + "0" + "\">";
       String luceneIndex1Config = "<" + LuceneXmlConstants.PREFIX + ":" + LuceneXmlConstants.INDEX
-          + " xmlns:lucene=\"" + LuceneXmlConstants.NAMESPACE + "\" " + LuceneXmlConstants.NAME
+          + " " + LuceneXmlConstants.NAME
           + "=\"" + INDEX_NAME + "1" + "\">";
       if (verifyIndexesExist) {
         assertThat(xmlContent).contains(luceneIndex0Config);
diff --git a/geode-lucene/src/main/java/org/apache/geode/cache/lucene/internal/cli/functions/LuceneCreateIndexFunction.java b/geode-lucene/src/main/java/org/apache/geode/cache/lucene/internal/cli/functions/LuceneCreateIndexFunction.java
index 4c2c3cd..e789ec0 100644
--- a/geode-lucene/src/main/java/org/apache/geode/cache/lucene/internal/cli/functions/LuceneCreateIndexFunction.java
+++ b/geode-lucene/src/main/java/org/apache/geode/cache/lucene/internal/cli/functions/LuceneCreateIndexFunction.java
@@ -103,7 +103,7 @@ public class LuceneCreateIndexFunction implements InternalFunction {
       if (LuceneServiceImpl.LUCENE_REINDEX) {
         indexFactory.create(indexName, regionPath, true);
         if (cache.getRegion(regionPath) != null) {
-          xmlEntity = getXmlEntity(indexName, regionPath);
+          xmlEntity = getXmlEntity(regionPath);
         }
       } else {
         indexFactory.create(indexName, regionPath, false);
@@ -117,7 +117,7 @@ public class LuceneCreateIndexFunction implements InternalFunction {
     }
   }
 
-  protected XmlEntity getXmlEntity(String indexName, String regionPath) {
+  protected XmlEntity getXmlEntity(String regionPath) {
     String regionName = StringUtils.stripStart(regionPath, "/");
     return new XmlEntity(CacheXml.REGION, "name", regionName);
   }
diff --git a/geode-lucene/src/main/java/org/apache/geode/cache/lucene/management/configuration/Index.java b/geode-lucene/src/main/java/org/apache/geode/cache/lucene/management/configuration/Index.java
new file mode 100644
index 0000000..b87ed42
--- /dev/null
+++ b/geode-lucene/src/main/java/org/apache/geode/cache/lucene/management/configuration/Index.java
@@ -0,0 +1,237 @@
+
+/*
+ * 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.cache.lucene.management.configuration;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+
+import org.apache.geode.cache.configuration.CacheElement;
+import org.apache.geode.cache.configuration.DeclarableType;
+import org.apache.geode.cache.configuration.XSDRootElement;
+
+
+/**
+ * <p>
+ * Java class for anonymous complex type.
+ *
+ * <p>
+ * The following schema fragment specifies the expected content contained within this class.
+ *
+ * <pre>
+ * &lt;complexType>
+ *   &lt;complexContent>
+ *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *       &lt;sequence>
+ *         &lt;element name="field" maxOccurs="unbounded">
+ *           &lt;complexType>
+ *             &lt;complexContent>
+ *               &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *                 &lt;attribute name="name" type="{http://www.w3.org/2001/XMLSchema}string" />
+ *                 &lt;attribute name="analyzer" type="{http://www.w3.org/2001/XMLSchema}string" />
+ *               &lt;/restriction>
+ *             &lt;/complexContent>
+ *           &lt;/complexType>
+ *         &lt;/element>
+ *         &lt;element name="serializer" type="{http://geode.apache.org/schema/cache}declarable-type" minOccurs="0"/>
+ *       &lt;/sequence>
+ *       &lt;attribute name="name" type="{http://www.w3.org/2001/XMLSchema}string" />
+ *     &lt;/restriction>
+ *   &lt;/complexContent>
+ * &lt;/complexType>
+ * </pre>
+ *
+ *
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "", propOrder = {
+    "field",
+    "serializer"
+})
+@XmlRootElement(name = "index", namespace = "http://geode.apache.org/schema/lucene")
+@XSDRootElement(namespace = "http://geode.apache.org/schema/lucene",
+    schemaLocation = "http://geode.apache.org/schema/lucene/lucene-1.0.xsd")
+public class Index implements CacheElement {
+  @XmlElement(namespace = "http://geode.apache.org/schema/lucene", required = true)
+  protected List<Index.Field> field;
+  @XmlElement(namespace = "http://geode.apache.org/schema/lucene")
+  protected DeclarableType serializer;
+  @XmlAttribute(name = "name")
+  protected String name;
+
+  /**
+   * Gets the value of the field property.
+   *
+   * <p>
+   * This accessor method returns a reference to the live list,
+   * not a snapshot. Therefore any modification you make to the
+   * returned list will be present inside the JAXB object.
+   * This is why there is not a <CODE>set</CODE> method for the field property.
+   *
+   * <p>
+   * For example, to add a new item, do as follows:
+   *
+   * <pre>
+   * getField().add(newItem);
+   * </pre>
+   *
+   *
+   * <p>
+   * Objects of the following type(s) are allowed in the list
+   * {@link Index.Field }
+   *
+   *
+   */
+  public List<Index.Field> getField() {
+    if (field == null) {
+      field = new ArrayList<Index.Field>();
+    }
+    return this.field;
+  }
+
+  /**
+   * Gets the value of the serializer property.
+   *
+   * possible object is
+   * {@link DeclarableType }
+   *
+   */
+  public DeclarableType getSerializer() {
+    return serializer;
+  }
+
+  /**
+   * Sets the value of the serializer property.
+   *
+   * allowed object is
+   * {@link DeclarableType }
+   *
+   */
+  public void setSerializer(DeclarableType value) {
+    this.serializer = value;
+  }
+
+  /**
+   * Gets the value of the name property.
+   *
+   * possible object is
+   * {@link String }
+   *
+   */
+  public String getName() {
+    return name;
+  }
+
+  /**
+   * Sets the value of the name property.
+   *
+   * allowed object is
+   * {@link String }
+   *
+   */
+  public void setName(String value) {
+    this.name = value;
+  }
+
+  @Override
+  public String getId() {
+    return getName();
+  }
+
+
+  /**
+   * <p>
+   * Java class for anonymous complex type.
+   *
+   * <p>
+   * The following schema fragment specifies the expected content contained within this class.
+   *
+   * <pre>
+   * &lt;complexType>
+   *   &lt;complexContent>
+   *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+   *       &lt;attribute name="name" type="{http://www.w3.org/2001/XMLSchema}string" />
+   *       &lt;attribute name="analyzer" type="{http://www.w3.org/2001/XMLSchema}string" />
+   *     &lt;/restriction>
+   *   &lt;/complexContent>
+   * &lt;/complexType>
+   * </pre>
+   *
+   *
+   */
+  @XmlAccessorType(XmlAccessType.FIELD)
+  @XmlType(name = "")
+  public static class Field {
+
+    @XmlAttribute(name = "name")
+    protected String name;
+    @XmlAttribute(name = "analyzer")
+    protected String analyzer;
+
+    /**
+     * Gets the value of the name property.
+     *
+     * possible object is
+     * {@link String }
+     *
+     */
+    public String getName() {
+      return name;
+    }
+
+    /**
+     * Sets the value of the name property.
+     *
+     * allowed object is
+     * {@link String }
+     *
+     */
+    public void setName(String value) {
+      this.name = value;
+    }
+
+    /**
+     * Gets the value of the analyzer property.
+     *
+     * possible object is
+     * {@link String }
+     *
+     */
+    public String getAnalyzer() {
+      return analyzer;
+    }
+
+    /**
+     * Sets the value of the analyzer property.
+     *
+     * allowed object is
+     * {@link String }
+     *
+     */
+    public void setAnalyzer(String value) {
+      this.analyzer = value;
+    }
+
+  }
+
+}
diff --git a/geode-lucene/src/main/java/org/apache/geode/cache/lucene/management/configuration/package-info.java b/geode-lucene/src/main/java/org/apache/geode/cache/lucene/management/configuration/package-info.java
new file mode 100644
index 0000000..2d2c0f1
--- /dev/null
+++ b/geode-lucene/src/main/java/org/apache/geode/cache/lucene/management/configuration/package-info.java
@@ -0,0 +1,22 @@
+/*
+ * 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.
+ */
+
+@XmlSchema(namespace = "http://geode.apache.org/schema/lucene",
+    xmlns = {@XmlNs(prefix = "lucene", namespaceURI = "http://geode.apache.org/schema/lucene")},
+    elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
+package org.apache.geode.cache.lucene.management.configuration;
+
+import javax.xml.bind.annotation.XmlNs;
+import javax.xml.bind.annotation.XmlSchema;
diff --git a/geode-lucene/src/main/resources/org/apache/geode/internal/sanctioned-geode-lucene-serializables.txt b/geode-lucene/src/main/resources/org/apache/geode/internal/sanctioned-geode-lucene-serializables.txt
index 4f0a2b2..491a993 100755
--- a/geode-lucene/src/main/resources/org/apache/geode/internal/sanctioned-geode-lucene-serializables.txt
+++ b/geode-lucene/src/main/resources/org/apache/geode/internal/sanctioned-geode-lucene-serializables.txt
@@ -2,6 +2,7 @@ org/apache/geode/cache/lucene/LuceneIndexDestroyedException,false,indexName:java
 org/apache/geode/cache/lucene/LuceneIndexExistsException,false,indexName:java/lang/String,regionPath:java/lang/String
 org/apache/geode/cache/lucene/LuceneIndexNotFoundException,false,indexName:java/lang/String,regionPath:java/lang/String
 org/apache/geode/cache/lucene/LuceneQueryException,false
+org/apache/geode/cache/lucene/management/configuration/Index,false,field:java/util/List,name:java/lang/String,serializer:org/apache/geode/cache/configuration/DeclarableType
 org/apache/geode/cache/lucene/internal/LuceneIndexCreationInProgressException,false
 org/apache/geode/cache/lucene/internal/cli/LuceneDestroyIndexInfo,false,definedDestroyOnly:boolean
 org/apache/geode/cache/lucene/internal/cli/LuceneFunctionSerializable,false,indexName:java/lang/String,regionPath:java/lang/String


[geode] 01/03: GEODE-5971: Refactor CreateRegionCommand to extend SingleGfshCommand

Posted by ji...@apache.org.
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

commit e9f5cd35b64ffa63ca6ebddee8aba3ef91a76d4b
Author: Aditya Anchuri <aa...@pivotal.io>
AuthorDate: Thu Nov 8 10:06:36 2018 -0800

    GEODE-5971: Refactor CreateRegionCommand to extend SingleGfshCommand
    
    - Store config via generating a RegionConfig object rather than an XML
    entity
    
    Signed-off-by: Peter Tran <pt...@pivotal.io>
    Signed-off-by: Aditya Anchuri <aa...@pivotal.io>
    Signed-off-by: Jens Deppe <jd...@pivotal.io>
---
 .gitignore                                         |   1 +
 .../cli/commands/ConfigureEvictionThroughGfsh.java |   6 +-
 .../integrationTest/resources/assembly_content.txt |   2 +-
 geode-core/build.gradle                            |   1 -
 .../CreateDefinedIndexesCommandDUnitTest.java      |  13 +-
 .../cli/commands/CreateRegionCommandDUnitTest.java | 120 +++-
 ...egionCommandPersistsConfigurationDUnitTest.java | 789 +++++++++++++++++++++
 .../ImportOldClusterConfigDUnitTest.java           |   2 +-
 .../java/org/apache/geode/cache/DataPolicy.java    |   7 +
 .../org/apache/geode/cache/EvictionAttributes.java |  39 +
 .../org/apache/geode/cache/ExpirationAction.java   |  15 +
 .../apache/geode/cache/ExpirationAttributes.java   |  16 +-
 .../apache/geode/cache/PartitionAttributes.java    |  19 +
 .../cache/configuration/RegionAttributesType.java  |  11 +
 .../InternalConfigurationPersistenceService.java   |  23 -
 .../apache/geode/internal/config/JAXBService.java  |   4 +-
 .../internal/cli/commands/AlterRegionCommand.java  |   3 +-
 .../internal/cli/commands/CreateRegionCommand.java | 123 +++-
 .../cli/domain/RegionAttributeGetFunction.java     |  22 +
 .../cli/domain/RegionAttributeSetFunction.java     |  22 +
 .../internal/cli/domain/RegionConfigFactory.java   | 331 +++++++++
 .../cli/functions/RegionAlterFunction.java         |  12 +-
 .../cli/functions/RegionCreateFunction.java        | 157 ++--
 .../internal/cli/functions/RegionFunctionArgs.java |  86 ++-
 .../management/internal/cli/i18n/CliStrings.java   |   2 +
 .../management/internal/cli/util/RegionPath.java   |  16 +
 .../geode/redis/internal/RegionProvider.java       |  20 +-
 .../cli/commands/CreateRegionCommandTest.java      |  26 +-
 .../cli/domain/RegionConfigFactoryTest.java        | 273 +++++++
 .../cli/functions/RegionFunctionArgsTest.java      |  45 +-
 .../cli/commands/CreateRegionCommandDUnitTest.java |  55 +-
 31 files changed, 2061 insertions(+), 200 deletions(-)

diff --git a/.gitignore b/.gitignore
index 47d635b..1525f4a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -28,6 +28,7 @@ out/
 *.orig
 geode-pulse/screenshots/
 /jpf.properties
+geode-assembly/assembly_content.txt
 
 .git-together
 bin/
diff --git a/geode-assembly/src/acceptanceTest/java/org/apache/geode/management/internal/cli/commands/ConfigureEvictionThroughGfsh.java b/geode-assembly/src/acceptanceTest/java/org/apache/geode/management/internal/cli/commands/ConfigureEvictionThroughGfsh.java
index 125d327..29ea9a5 100644
--- a/geode-assembly/src/acceptanceTest/java/org/apache/geode/management/internal/cli/commands/ConfigureEvictionThroughGfsh.java
+++ b/geode-assembly/src/acceptanceTest/java/org/apache/geode/management/internal/cli/commands/ConfigureEvictionThroughGfsh.java
@@ -57,7 +57,7 @@ public class ConfigureEvictionThroughGfsh {
             "create region --name=region6 --eviction-action=local-destroy --eviction-entry-count=1000 --type=REPLICATE_PERSISTENT")
         .expectFailure().execute(gfsh);
     assertThat(execution.getOutputText()).contains(
-        "ERROR: An Eviction Controller with local destroy eviction action is incompatible with");
+        "An Eviction Controller with local destroy eviction action is incompatible with");
 
     execution = GfshScript
         .of("connect --locator=localhost[10334]", "describe region --name=region1").execute(gfsh);
@@ -112,7 +112,7 @@ public class ConfigureEvictionThroughGfsh {
             "create region --name=region6 --eviction-action=local-destroy --eviction-max-memory=1000 --type=REPLICATE_PERSISTENT")
         .expectFailure().execute(gfsh);
     assertThat(execution.getOutputText()).contains(
-        "ERROR: An Eviction Controller with local destroy eviction action is incompatible with");
+        "An Eviction Controller with local destroy eviction action is incompatible with");
 
     execution = GfshScript
         .of("connect --locator=localhost[10334]", "describe region --name=region1").execute(gfsh);
@@ -181,7 +181,7 @@ public class ConfigureEvictionThroughGfsh {
             "create region --name=region6 --eviction-action=local-destroy --eviction-max-memory=1000 --eviction-object-sizer=MySizer --type=REPLICATE_PERSISTENT")
         .expectFailure().execute(gfsh);
     assertThat(execution.getOutputText()).contains(
-        "ERROR: An Eviction Controller with local destroy eviction action is incompatible with");
+        "An Eviction Controller with local destroy eviction action is incompatible with");
 
     execution = GfshScript
         .of("connect --locator=localhost[10334]", "describe region --name=region1").execute(gfsh);
diff --git a/geode-assembly/src/integrationTest/resources/assembly_content.txt b/geode-assembly/src/integrationTest/resources/assembly_content.txt
index 9cd4c19..f216ab3 100644
--- a/geode-assembly/src/integrationTest/resources/assembly_content.txt
+++ b/geode-assembly/src/integrationTest/resources/assembly_content.txt
@@ -957,4 +957,4 @@ tools/Modules/Apache_Geode_Modules-0.0.0-AppServer.zip
 tools/Modules/Apache_Geode_Modules-0.0.0-Tomcat.zip
 tools/Modules/Apache_Geode_Modules-0.0.0-tcServer.zip
 tools/Modules/Apache_Geode_Modules-0.0.0-tcServer30.zip
-tools/Pulse/geode-pulse-0.0.0.war
+tools/Pulse/geode-pulse-0.0.0.war
\ No newline at end of file
diff --git a/geode-core/build.gradle b/geode-core/build.gradle
index 3f89a6f..668b2f1 100755
--- a/geode-core/build.gradle
+++ b/geode-core/build.gradle
@@ -15,7 +15,6 @@
  * limitations under the License.
  */
 
-
 apply plugin: 'antlr'
 apply plugin: 'me.champeau.gradle.jmh'
 
diff --git a/geode-core/src/distributedTest/java/org/apache/geode/management/internal/cli/commands/CreateDefinedIndexesCommandDUnitTest.java b/geode-core/src/distributedTest/java/org/apache/geode/management/internal/cli/commands/CreateDefinedIndexesCommandDUnitTest.java
index 093a536..9b2df1b 100644
--- a/geode-core/src/distributedTest/java/org/apache/geode/management/internal/cli/commands/CreateDefinedIndexesCommandDUnitTest.java
+++ b/geode-core/src/distributedTest/java/org/apache/geode/management/internal/cli/commands/CreateDefinedIndexesCommandDUnitTest.java
@@ -15,6 +15,7 @@
 
 package org.apache.geode.management.internal.cli.commands;
 
+import static org.apache.geode.management.internal.cli.result.model.ResultModel.MEMBER_STATUS_SECTION;
 import static org.assertj.core.api.Assertions.assertThat;
 
 import java.util.List;
@@ -188,13 +189,15 @@ public class CreateDefinedIndexesCommandDUnitTest {
     CommandResult result = gfsh
         .executeCommand("create region --name=" + region1Name + " --type=REPLICATE --group=group1");
     assertThat(result.getStatus()).isEqualTo(Result.Status.OK);
-    assertThat(result.getMapFromTableContent("0", "0").get("Member")).contains("server-1",
+    assertThat(result.getMapFromTableContent(MEMBER_STATUS_SECTION).get("Member")).contains(
+        "server-1",
         "server-2");
 
     result = gfsh
         .executeCommand("create region --name=" + region2Name + " --type=REPLICATE --group=group1");
     assertThat(result.getStatus()).isEqualTo(Result.Status.OK);
-    assertThat(result.getMapFromTableContent("0", "0").get("Member")).contains("server-1",
+    assertThat(result.getMapFromTableContent(MEMBER_STATUS_SECTION).get("Member")).contains(
+        "server-1",
         "server-2");
 
     VMProvider.invokeInEveryMember(() -> {
@@ -251,13 +254,15 @@ public class CreateDefinedIndexesCommandDUnitTest {
     CommandResult result = gfsh
         .executeCommand("create region --name=" + region1Name + " --type=REPLICATE --group=group1");
     assertThat(result.getStatus()).isEqualTo(Result.Status.OK);
-    assertThat(result.getMapFromTableContent("0", "0").get("Member")).contains("server-1",
+    assertThat(result.getMapFromTableContent(MEMBER_STATUS_SECTION).get("Member")).contains(
+        "server-1",
         "server-2");
 
     result = gfsh
         .executeCommand("create region --name=" + region2Name + " --type=REPLICATE --group=group2");
     assertThat(result.getStatus()).isEqualTo(Result.Status.OK);
-    assertThat(result.getMapFromTableContent("0", "0").get("Member")).contains("server-3");
+    assertThat(result.getMapFromTableContent(MEMBER_STATUS_SECTION).get("Member"))
+        .contains("server-3");
 
     gfsh.executeAndAssertThat(
         "define index --name=" + index1Name + " --expression=value1 --region=" + region1Name)
diff --git a/geode-core/src/distributedTest/java/org/apache/geode/management/internal/cli/commands/CreateRegionCommandDUnitTest.java b/geode-core/src/distributedTest/java/org/apache/geode/management/internal/cli/commands/CreateRegionCommandDUnitTest.java
index 8d8dc19..0c50623 100644
--- a/geode-core/src/distributedTest/java/org/apache/geode/management/internal/cli/commands/CreateRegionCommandDUnitTest.java
+++ b/geode-core/src/distributedTest/java/org/apache/geode/management/internal/cli/commands/CreateRegionCommandDUnitTest.java
@@ -20,10 +20,12 @@ import static org.assertj.core.api.Assertions.assertThat;
 import java.io.File;
 import java.io.Serializable;
 import java.util.Arrays;
+import java.util.List;
 import java.util.stream.Collectors;
 
 import org.junit.BeforeClass;
 import org.junit.ClassRule;
+import org.junit.Ignore;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.experimental.categories.Category;
@@ -31,13 +33,19 @@ import org.junit.rules.TemporaryFolder;
 import org.junit.rules.TestName;
 
 import org.apache.geode.cache.Cache;
+import org.apache.geode.cache.Declarable;
+import org.apache.geode.cache.EntryOperation;
 import org.apache.geode.cache.PartitionResolver;
 import org.apache.geode.cache.Region;
+import org.apache.geode.cache.asyncqueue.AsyncEvent;
+import org.apache.geode.cache.asyncqueue.AsyncEventListener;
 import org.apache.geode.cache.configuration.CacheConfig;
 import org.apache.geode.cache.configuration.CacheElement;
 import org.apache.geode.cache.configuration.RegionConfig;
 import org.apache.geode.cache.util.CacheListenerAdapter;
+import org.apache.geode.compression.Compressor;
 import org.apache.geode.compression.SnappyCompressor;
+import org.apache.geode.internal.cache.InternalRegion;
 import org.apache.geode.internal.cache.PartitionedRegion;
 import org.apache.geode.internal.cache.RegionEntryContext;
 import org.apache.geode.test.compiler.JarBuilder;
@@ -59,6 +67,37 @@ public class CreateRegionCommandDUnitTest {
       implements Serializable {
   }
 
+  public static class DummyAEQListener implements AsyncEventListener, Declarable {
+    @Override
+    public boolean processEvents(List<AsyncEvent> events) {
+      return false;
+    }
+  }
+
+  public static class DummyPartitionResolver implements PartitionResolver, Declarable {
+    @Override
+    public Object getRoutingObject(EntryOperation opDetails) {
+      return null;
+    }
+
+    @Override
+    public String getName() {
+      return "dummy";
+    }
+  }
+
+  public static class DummyCompressor implements Compressor, Declarable {
+    @Override
+    public byte[] compress(byte[] input) {
+      return new byte[0];
+    }
+
+    @Override
+    public byte[] decompress(byte[] input) {
+      return new byte[0];
+    }
+  }
+
   @ClassRule
   public static ClusterStartupRule lsRule = new ClusterStartupRule();
 
@@ -230,6 +269,7 @@ public class CreateRegionCommandDUnitTest {
     gfsh.executeAndAssertThat("destroy region --name=/TEMPLATE").statusIsSuccess();
   }
 
+
   @Test
   public void cannotSetRegionExpirationForPartitionedTemplate() {
     gfsh.executeAndAssertThat("create region --name=/TEMPLATE --type=PARTITION")
@@ -431,11 +471,12 @@ public class CreateRegionCommandDUnitTest {
   }
 
   @Test
-  public void startWithReplicateProxyThenPartitionRegion() {
+  public void startWithReplicateProxyThenPartitionRegion() throws Exception {
     String regionName = testName.getMethodName();
     gfsh.executeAndAssertThat(
         "create region --type=REPLICATE_PROXY --group=group1 --name=" + regionName)
         .statusIsSuccess().tableHasRowWithValues("Member", "server-1");
+
     gfsh.executeAndAssertThat("create region --type=PARTITION --group=group2 --name=" + regionName)
         .statusIsError().containsOutput("The existing region is not a partitioned region");
     gfsh.executeAndAssertThat(
@@ -560,6 +601,83 @@ public class CreateRegionCommandDUnitTest {
         .containsOutput("Region /startWithLocalRegion already exists on the cluster");
   }
 
+  @Test
+  public void cannotDisableCloningWhenCompressorIsSet() {
+    String regionName = testName.getMethodName();
+    gfsh.executeAndAssertThat("create region"
+        + " --name=" + regionName
+        + " --type=REPLICATE"
+        + " --compressor=" + DummyCompressor.class.getName()
+        + " --enable-cloning=false").statusIsError();
+  }
+
+  /**
+   * Ignored this test until we refactor the FetchRegionAttributesFunction to not use
+   * AttributesFactory, and instead use RegionConfig, which we will do as part of implementing
+   * GEODE-6103
+   */
+  @Ignore
+  @Test
+  public void testCreateRegionFromTemplateWithAsyncEventListeners() {
+    String queueId = "queue1";
+    gfsh.executeAndAssertThat(
+        "create async-event-queue --id=" + queueId
+            + " --listener=" + CreateRegionCommandDUnitTest.DummyAEQListener.class.getName())
+        .statusIsSuccess();
+
+    String regionName = testName.getMethodName();
+    gfsh.executeAndAssertThat(
+        "create region --name=" + regionName
+            + " --type=REPLICATE"
+            + " --async-event-queue-id=" + queueId)
+        .statusIsSuccess();
+
+    gfsh.executeAndAssertThat(
+        "create region --name=" + regionName + "-from-template"
+            + " --template-region=" + regionName)
+        .statusIsSuccess();
+
+    server1.invoke(() -> {
+      Region regionFromTemplate = ClusterStartupRule.getCache()
+          .getRegion(regionName + "-from-template");
+      assertThat(regionFromTemplate).isNotNull();
+      assertThat(((InternalRegion) regionFromTemplate).getAsyncEventQueueIds())
+          .contains(queueId);
+    });
+  }
+
+  /**
+   * Ignored this test until we refactor the FetchRegionAttributesFunction to not use
+   * AttributesFactory, and instead use RegionConfig, which we will do as part of implementing
+   * GEODE-6103
+   */
+  @Ignore
+  @Test
+  public void testCreateRegionFromTemplateWithPartitionResolver() {
+    String regionName = testName.getMethodName();
+    String regionFromTemplateName = regionName + "-from-template";
+
+    gfsh.executeAndAssertThat("create region"
+        + " --name=" + regionName
+        + " --type=PARTITION"
+        + " --partition-resolver=" + DummyPartitionResolver.class.getName()).statusIsSuccess();
+    gfsh.executeAndAssertThat("create region"
+        + " --name=" + regionFromTemplateName
+        + " --template-region=" + regionName).statusIsSuccess();
+
+    server1.invoke(() -> {
+      Region regionFromTemplate = ClusterStartupRule.getCache()
+          .getRegion(regionName + "-from-template");
+      assertThat(regionFromTemplate).isNotNull();
+      assertThat(((InternalRegion) regionFromTemplate).getPartitionAttributes()
+          .getPartitionResolver())
+              .isNotNull();
+      assertThat(((InternalRegion) regionFromTemplate).getPartitionAttributes()
+          .getPartitionResolver().getName())
+              .isEqualTo(DummyPartitionResolver.class.getName());
+    });
+  }
+
   private String getUniversalClassCode(String classname) {
     String code = "package io.pivotal;" + "import org.apache.geode.cache.CacheLoader;"
         + "import org.apache.geode.cache.CacheLoaderException;"
diff --git a/geode-core/src/distributedTest/java/org/apache/geode/management/internal/cli/commands/CreateRegionCommandPersistsConfigurationDUnitTest.java b/geode-core/src/distributedTest/java/org/apache/geode/management/internal/cli/commands/CreateRegionCommandPersistsConfigurationDUnitTest.java
new file mode 100644
index 0000000..275fac9
--- /dev/null
+++ b/geode-core/src/distributedTest/java/org/apache/geode/management/internal/cli/commands/CreateRegionCommandPersistsConfigurationDUnitTest.java
@@ -0,0 +1,789 @@
+/*
+ * 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 java.util.Arrays;
+import java.util.List;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.rules.TestName;
+
+import org.apache.geode.cache.CacheLoader;
+import org.apache.geode.cache.CacheLoaderException;
+import org.apache.geode.cache.CustomExpiry;
+import org.apache.geode.cache.Declarable;
+import org.apache.geode.cache.EntryOperation;
+import org.apache.geode.cache.ExpirationAttributes;
+import org.apache.geode.cache.LoaderHelper;
+import org.apache.geode.cache.PartitionResolver;
+import org.apache.geode.cache.Region;
+import org.apache.geode.cache.configuration.CacheConfig;
+import org.apache.geode.cache.configuration.CacheElement;
+import org.apache.geode.cache.configuration.ExpirationAttributesType;
+import org.apache.geode.cache.configuration.RegionAttributesDataPolicy;
+import org.apache.geode.cache.configuration.RegionAttributesType;
+import org.apache.geode.cache.configuration.RegionConfig;
+import org.apache.geode.cache.util.CacheListenerAdapter;
+import org.apache.geode.cache.util.CacheWriterAdapter;
+import org.apache.geode.compression.Compressor;
+import org.apache.geode.distributed.internal.InternalConfigurationPersistenceService;
+import org.apache.geode.test.dunit.rules.ClusterStartupRule;
+import org.apache.geode.test.dunit.rules.MemberVM;
+import org.apache.geode.test.junit.categories.RegionsTest;
+import org.apache.geode.test.junit.rules.GfshCommandRule;
+import org.apache.geode.test.junit.rules.serializable.SerializableTestName;
+
+@Category({RegionsTest.class})
+public class CreateRegionCommandPersistsConfigurationDUnitTest {
+
+  private MemberVM locator, server1;
+
+  @Rule
+  public ClusterStartupRule clusterRule = new ClusterStartupRule();
+
+  @Rule
+  public GfshCommandRule gfsh = new GfshCommandRule();
+
+  @Rule
+  public TestName testName = new SerializableTestName();
+
+  public static class DummyCacheListener extends CacheListenerAdapter {
+  }
+
+  public static class DummyCustomExpiry implements CustomExpiry, Declarable {
+    @Override
+    public ExpirationAttributes getExpiry(Region.Entry entry) {
+      return null;
+    }
+  }
+
+  public static class DummyPartitionResolver implements PartitionResolver, Declarable {
+    @Override
+    public Object getRoutingObject(EntryOperation opDetails) {
+      return null;
+    }
+
+    @Override
+    public String getName() {
+      return "dummy";
+    }
+  }
+
+  public static class DummyCompressor implements Compressor, Declarable {
+    @Override
+    public byte[] compress(byte[] input) {
+      return new byte[0];
+    }
+
+    @Override
+    public byte[] decompress(byte[] input) {
+      return new byte[0];
+    }
+  }
+
+  public static class DummyCacheLoader implements CacheLoader, Declarable {
+    @Override
+    public Object load(LoaderHelper helper) throws CacheLoaderException {
+      return null;
+    }
+  }
+
+  public static class DummyCacheWriter extends CacheWriterAdapter {
+  }
+
+  @Before
+  public void before() throws Exception {
+    locator = clusterRule.startLocatorVM(0);
+    server1 = clusterRule.startServerVM(1, locator.getPort());
+
+    gfsh.connectAndVerify(locator);
+  }
+
+  @Test
+  public void createRegionPersistsEmptyConfig() {
+    String regionName = testName.getMethodName();
+    gfsh.executeAndAssertThat("create region --name=" + regionName + " --type=REPLICATE")
+        .statusIsSuccess();
+
+    server1.stop();
+    server1 = clusterRule.startServerVM(1, "group1", locator.getPort());
+
+    gfsh.executeAndAssertThat("list regions")
+        .statusIsSuccess().containsOutput(regionName);
+
+    locator.invoke(() -> {
+      InternalConfigurationPersistenceService cc =
+          ClusterStartupRule.getLocator().getConfigurationPersistenceService();
+      CacheConfig config = cc.getCacheConfig("cluster");
+
+      List<RegionConfig> regions = config.getRegions();
+      assertThat(regions).isNotEmpty();
+      RegionConfig regionConfig = regions.get(0);
+      assertThat(regionConfig).isNotNull();
+      assertThat(regionConfig.getName()).isEqualTo(regionName);
+      assertThat(regionConfig.getIndexes()).isEmpty();
+      assertThat(regionConfig.getRegions()).isEmpty();
+      assertThat(regionConfig.getEntries()).isEmpty();
+      assertThat(regionConfig.getCustomRegionElements()).isEmpty();
+    });
+  }
+
+  @Test
+  public void createRegionPersistsConfigParams() {
+    String regionName = testName.getMethodName();
+    gfsh.executeAndAssertThat("create region --name=" + regionName + " --type=PARTITION"
+        + " --enable-statistics=true" + " --enable-async-conflation=true"
+        + " --entry-idle-time-expiration=100").statusIsSuccess();
+
+    server1.stop();
+    server1 = clusterRule.startServerVM(1, "group1", locator.getPort());
+
+    gfsh.executeAndAssertThat("list regions")
+        .statusIsSuccess().containsOutput(regionName);
+
+    locator.invoke(() -> {
+      InternalConfigurationPersistenceService cc =
+          ClusterStartupRule.getLocator().getConfigurationPersistenceService();
+      CacheConfig config = cc.getCacheConfig("cluster");
+
+      List<RegionConfig> regions = config.getRegions();
+      assertThat(regions).isNotEmpty();
+      RegionConfig regionConfig = regions.get(0);
+      assertThat(regionConfig).isNotNull();
+      assertThat(regionConfig.getName()).isEqualTo(regionName);
+      assertThat(regionConfig.getRegionAttributes()).hasSize(1);
+
+      RegionAttributesType attr = regionConfig.getRegionAttributes().get(0);
+      assertThat(attr.isStatisticsEnabled()).isTrue();
+      assertThat(attr.isEnableAsyncConflation()).isTrue();
+
+      ExpirationAttributesType entryIdleTimeExp = attr.getEntryIdleTime().getExpirationAttributes();
+      assertThat(entryIdleTimeExp.getTimeout()).isEqualTo("100");
+    });
+
+    server1.invoke(() -> {
+      Region<?, ?> region = ClusterStartupRule.getCache().getRegion(regionName);
+      assertThat(region.getAttributes().getStatisticsEnabled())
+          .describedAs("Expecting statistics to be enabled")
+          .isTrue();
+      assertThat(region.getAttributes().getEnableAsyncConflation())
+          .describedAs("Expecting async conflation to be enabled")
+          .isTrue();
+      assertThat(region.getAttributes().getEntryIdleTimeout().getTimeout())
+          .describedAs("Expecting entry idle time exp timeout to be 100")
+          .isEqualTo(100);
+    });
+  }
+
+  @Test
+  public void createRegionFromTemplateCreatesCorrectConfig() {
+    String regionName = testName.getMethodName();
+    String templateRegionName = regionName + "_template";
+    gfsh.executeAndAssertThat("create region"
+        + " --name=" + templateRegionName
+        + " --type=PARTITION"
+        + " --cache-listener=" + DummyCacheListener.class.getName()
+        + " --enable-statistics=true"
+        + " --enable-async-conflation=true"
+        + " --entry-idle-time-expiration=100").statusIsSuccess();
+
+    gfsh.executeAndAssertThat(
+        "create region --name=" + regionName + " --template-region=" + templateRegionName);
+
+    locator.invoke(() -> {
+      InternalConfigurationPersistenceService cc =
+          ClusterStartupRule.getLocator().getConfigurationPersistenceService();
+      CacheConfig config = cc.getCacheConfig("cluster");
+
+      List<RegionConfig> regions = config.getRegions();
+      assertThat(regions).isNotEmpty();
+      RegionConfig regionConfig = CacheElement.findElement(config.getRegions(), regionName);
+
+      assertThat(regionConfig).isNotNull();
+      assertThat(regionConfig.getName()).isEqualTo(regionName);
+      assertThat(regionConfig.getRegionAttributes()).hasSize(1);
+
+      RegionAttributesType attr = regionConfig.getRegionAttributes().get(0);
+      assertThat(attr.isStatisticsEnabled()).isTrue();
+      assertThat(attr.isEnableAsyncConflation()).isTrue();
+
+      ExpirationAttributesType entryIdleTimeExp = attr.getEntryIdleTime().getExpirationAttributes();
+      assertThat(entryIdleTimeExp.getTimeout()).isEqualTo("100");
+    });
+  }
+
+  @Test
+  public void createRegionAndValidateAllConfigIsPersistedForReplicatedRegion() {
+    String regionName = testName.getMethodName();
+    gfsh.executeAndAssertThat("create region"
+        + " --name=" + regionName
+        + " --type=REPLICATE"
+        + " --cache-listener=" + DummyCacheListener.class.getName()
+        + " --cache-loader=" + DummyCacheLoader.class.getName()
+        + " --cache-writer=" + DummyCacheWriter.class.getName()
+        + " --compressor=" + DummyCompressor.class.getName()
+        + " --enable-async-conflation=false"
+        + " --enable-concurrency-checks=false"
+        + " --enable-multicast=false"
+        + " --concurrency-level=1"
+        + " --enable-statistics=true"
+        + " --enable-subscription-conflation=true"
+        + " --entry-idle-time-expiration=100"
+        + " --entry-idle-time-expiration-action=local-destroy"
+        + " --entry-time-to-live-expiration=200"
+        + " --entry-time-to-live-expiration-action=local-destroy"
+        + " --eviction-action=local-destroy"
+        + " --key-constraint=" + Object.class.getName()
+        + " --off-heap=false"
+        + " --region-idle-time-expiration=100"
+        + " --region-idle-time-expiration-action=local-destroy"
+        + " --region-time-to-live-expiration=200"
+        + " --region-time-to-live-expiration-action=local-destroy"
+        + " --value-constraint=" + Object.class.getName()).statusIsSuccess();
+
+    String regionNameFromTemplate = regionName + "-from-template";
+    gfsh.executeAndAssertThat("create region --name=" + regionNameFromTemplate
+        + " --template-region=" + regionName)
+        .statusIsSuccess();
+
+    locator.invoke(() -> {
+      InternalConfigurationPersistenceService cc =
+          ClusterStartupRule.getLocator().getConfigurationPersistenceService();
+      CacheConfig config = cc.getCacheConfig("cluster");
+
+      List<RegionConfig> regions = config.getRegions();
+      assertThat(regions).isNotEmpty();
+      assertThat(regions).hasSize(2);
+
+      List<String> regionNames = Arrays.asList(regionName, regionNameFromTemplate);
+      regionNames.forEach(name -> {
+        RegionConfig regionConfig = CacheElement.findElement(config.getRegions(), name);
+        assertThat(regionConfig).isNotNull();
+        assertThat(regionConfig.getName()).isEqualTo(name);
+        assertThat(regionConfig.getRegionAttributes())
+            .describedAs("Expecting region attributes to exist")
+            .hasSize(1);
+
+        RegionAttributesType attr = regionConfig.getRegionAttributes().get(0);
+        assertThat(attr.getCacheListeners().get(0).toString())
+            .describedAs("Expecting one cache listener for region " + name)
+            .isEqualTo(DummyCacheListener.class.getName());
+        assertThat(attr.getCacheLoader().toString())
+            .describedAs("Expecting a DummyCacheLoader for region " + name)
+            .isEqualTo(DummyCacheLoader.class.getName());
+        assertThat(attr.getCacheWriter().toString())
+            .describedAs("Expecting a DummyCacheWriter for region " + name)
+            .isEqualTo(DummyCacheWriter.class.getName());
+        assertThat(attr.getCompressor().toString())
+            .describedAs("Expecting a DummyCompressor for region " + name)
+            .isEqualTo(DummyCompressor.class.getName());
+        assertThat(attr.isEnableAsyncConflation())
+            .describedAs("Expecting async conflation to not be enabled for region "
+                + name)
+            .isFalse();
+        assertThat(attr.isConcurrencyChecksEnabled())
+            .describedAs("Expecting concurrency checks not to be enabled for region "
+                + name)
+            .isFalse();
+        assertThat(attr.isMulticastEnabled())
+            .describedAs("Expecting multicast is not enabled for region " + name)
+            .isFalse();
+        assertThat(attr.getConcurrencyLevel())
+            .describedAs("Expecting concurrency level to be 1 for region " + name)
+            .isEqualTo("1");
+        assertThat(attr.isStatisticsEnabled())
+            .describedAs("Expecting statistics to be enabled for region " + name)
+            .isTrue();
+        assertThat(attr.isCloningEnabled())
+            .describedAs("Expecting cloning to be enabled for region " + name
+                + " since compressor is provided")
+            .isTrue();
+        assertThat(attr.isEnableSubscriptionConflation())
+            .describedAs("Expecting subscription conflation to be enabled for region "
+                + name)
+            .isTrue();
+        assertThat(attr.getEntryIdleTime().getExpirationAttributes().getTimeout())
+            .describedAs("Entry idle time timeout should be 100 for region " + name)
+            .isEqualTo("100");
+        assertThat(attr.getEntryIdleTime().getExpirationAttributes().getAction())
+            .describedAs("Entry idle time expiration action should be local-destroy for region "
+                + name)
+            .isEqualTo("local-destroy");
+        assertThat(attr.getEntryTimeToLive().getExpirationAttributes().getTimeout())
+            .describedAs("Expecting entry time to live expiration to be 200 for region "
+                + name)
+            .isEqualTo("200");
+        assertThat(attr.getEntryTimeToLive().getExpirationAttributes().getAction())
+            .describedAs("Entry time to live expiration action should be local-destroy "
+                + "for region " + name)
+            .isEqualTo("local-destroy");
+        assertThat(attr.getEvictionAttributes().getLruHeapPercentage().getAction().value())
+            .describedAs("Eviction action should be local-destroy for region " + name)
+            .isEqualTo("local-destroy");
+        assertThat(attr.getKeyConstraint())
+            .describedAs("Expected key constraint to be " + Object.class.getName() +
+                " for region " + name)
+            .isEqualTo(Object.class.getName());
+        assertThat(attr.isOffHeap())
+            .describedAs("Expected off heap to be false for region " + name)
+            .isFalse();
+        assertThat(attr.getRegionIdleTime().getExpirationAttributes().getTimeout())
+            .describedAs("Expecting region idle time expiration to be 100 for region "
+                + name)
+            .isEqualTo("100");
+        assertThat(attr.getRegionIdleTime().getExpirationAttributes().getAction())
+            .describedAs("Expecting region idle time expiration action to be "
+                + "local-destroy for region " + name)
+            .isEqualTo("local-destroy");
+        assertThat(attr.getRegionTimeToLive().getExpirationAttributes().getTimeout())
+            .describedAs("Expecting region idle time timeout to be 200 for "
+                + "region " + name)
+            .isEqualTo("200");
+        assertThat(attr.getRegionTimeToLive().getExpirationAttributes().getAction())
+            .describedAs("Expecting region ttl action to be local-destroy for "
+                + "region " + name)
+            .isEqualTo("local-destroy");
+        assertThat(attr.getValueConstraint())
+            .describedAs("Expecting value constraint to be Object.class for "
+                + "region " + name)
+            .isEqualTo(Object.class.getName());
+      });
+    });
+  }
+
+  @Test
+  public void createRegionDoesNotPersistEmptyOrDefaultEvictionAttributes() {
+    String regionName = testName.getMethodName();
+    gfsh.executeAndAssertThat("create region"
+        + " --name=" + regionName
+        + " --type=REPLICATE").statusIsSuccess();
+
+    locator.invoke(() -> {
+      InternalConfigurationPersistenceService cc =
+          ClusterStartupRule.getLocator().getConfigurationPersistenceService();
+      CacheConfig config = cc.getCacheConfig("cluster");
+
+      List<RegionConfig> regions = config.getRegions();
+      assertThat(regions).isNotEmpty();
+      assertThat(regions).hasSize(1);
+
+      List<String> regionNames = Arrays.asList(regionName);
+      regionNames.forEach(name -> {
+        RegionConfig regionConfig = CacheElement.findElement(config.getRegions(), name);
+        assertThat(regionConfig).isNotNull();
+        assertThat(regionConfig.getName()).isEqualTo(name);
+        assertThat(regionConfig.getRegionAttributes())
+            .describedAs("Expecting region attributes to exist")
+            .hasSize(1);
+
+        RegionAttributesType attr = regionConfig.getRegionAttributes().get(0);
+        assertThat(attr.getEvictionAttributes())
+            .describedAs("Eviction attributes should be null for " + name)
+            .isNull();
+      });
+    });
+  }
+
+  @Test
+  public void createRegionPersistsAEQConfig() {
+    String queueId = "queue1";
+    gfsh.executeAndAssertThat(
+        "create async-event-queue --id=" + queueId
+            + " --listener=" + CreateRegionCommandDUnitTest.DummyAEQListener.class.getName())
+        .statusIsSuccess();
+
+    String regionName = testName.getMethodName();
+    gfsh.executeAndAssertThat(
+        "create region --name=" + regionName
+            + " --type=REPLICATE"
+            + " --async-event-queue-id=" + queueId)
+        .statusIsSuccess();
+
+    locator.invoke(() -> {
+      InternalConfigurationPersistenceService cc =
+          ClusterStartupRule.getLocator().getConfigurationPersistenceService();
+      CacheConfig config = cc.getCacheConfig("cluster");
+
+      List<RegionConfig> regions = config.getRegions();
+      assertThat(regions).isNotEmpty();
+      assertThat(regions).hasSize(1);
+      RegionConfig regionConfig = CacheElement.findElement(regions, regionName);
+      assertThat(regionConfig.getRegionAttributes().get(0).getAsyncEventQueueIds())
+          .contains(queueId);
+    });
+  }
+
+  @Test
+  public void createRegionWithColocation() {
+    String regionName = testName.getMethodName();
+    String colocatedRegionName = regionName + "-colocated";
+    String colocatedRegionFromTemplateName = colocatedRegionName + "-from-template";
+
+    gfsh.executeAndAssertThat("create region"
+        + " --name=" + regionName
+        + " --type=PARTITION");
+    gfsh.executeAndAssertThat("create region"
+        + " --name=" + colocatedRegionName
+        + " --colocated-with=" + regionName
+        + " --type=PARTITION");
+
+    gfsh.executeAndAssertThat("create region"
+        + " --name=" + colocatedRegionFromTemplateName
+        + " --template-region=" + colocatedRegionName);
+
+    locator.invoke(() -> {
+      InternalConfigurationPersistenceService cc =
+          ClusterStartupRule.getLocator().getConfigurationPersistenceService();
+      CacheConfig config = cc.getCacheConfig("cluster");
+
+      List<RegionConfig> regions = config.getRegions();
+      assertThat(regions).isNotEmpty();
+      assertThat(regions).hasSize(3);
+
+      RegionConfig colocatedConfig = CacheElement.findElement(regions, colocatedRegionName);
+      assertThat(
+          colocatedConfig.getRegionAttributes().get(0).getPartitionAttributes().getColocatedWith())
+              .isEqualTo("/" + regionName);
+
+      RegionConfig colocatedConfigFromTemplate = CacheElement.findElement(regions,
+          colocatedRegionFromTemplateName);
+      assertThat(
+          colocatedConfigFromTemplate.getRegionAttributes().get(0).getPartitionAttributes()
+              .getColocatedWith())
+                  .isEqualTo("/" + regionName);
+    });
+  }
+
+  @Test
+  public void createRegionPersistsDiskstores() throws Exception {
+    String regionName = testName.getMethodName();
+    String store = "Store1";
+    gfsh.executeAndAssertThat("create disk-store"
+        + " --name=" + store
+        + " --dir=/tmp/foo").statusIsSuccess();
+
+    // Give disk store time to get created
+    Thread.sleep(2000);
+
+    gfsh.executeAndAssertThat("create region"
+        + " --name=" + regionName
+        + " --type=REPLICATE_PERSISTENT"
+        + " --disk-store=" + store
+        + " --enable-synchronous-disk=true").statusIsSuccess();
+
+    String regionNameFromTemplate = regionName + "-from-template";
+    gfsh.executeAndAssertThat("create region --name=" + regionNameFromTemplate
+        + " --template-region=" + regionName)
+        .statusIsSuccess();
+
+    locator.invoke(() -> {
+      InternalConfigurationPersistenceService cc =
+          ClusterStartupRule.getLocator().getConfigurationPersistenceService();
+      CacheConfig config = cc.getCacheConfig("cluster");
+
+      List<RegionConfig> regions = config.getRegions();
+      assertThat(regions).isNotEmpty();
+      assertThat(regions).hasSize(2);
+
+      List<String> regionNames = Arrays.asList(regionName, regionNameFromTemplate);
+      regionNames.forEach(name -> {
+        RegionConfig regionConfig = CacheElement.findElement(config.getRegions(), name);
+        assertThat(regionConfig).isNotNull();
+        assertThat(regionConfig.getName()).isEqualTo(name);
+
+        RegionAttributesType regionAttributes = regionConfig.getRegionAttributes().get(0);
+        assertThat(regionAttributes.getDiskStoreName())
+            .isEqualTo(store);
+        assertThat(regionAttributes.isDiskSynchronous())
+            .isTrue();
+      });
+    });
+  }
+
+  @Test
+  public void createRegionPersistsPartitionAttributes() {
+    String regionName = testName.getMethodName();
+    String regionFromTemplateName = regionName + "-from-template";
+
+    gfsh.executeAndAssertThat("create region"
+        + " --name=" + regionName
+        + " --type=PARTITION"
+        + " --recovery-delay=1"
+        + " --local-max-memory=1000"
+        + " --redundant-copies=1"
+        + " --startup-recovery-delay=1"
+        + " --total-max-memory=100"
+        + " --total-num-buckets=1").statusIsSuccess();
+    gfsh.executeAndAssertThat("create region"
+        + " --name=" + regionFromTemplateName
+        + " --template-region=" + regionName);
+
+    locator.invoke(() -> {
+      InternalConfigurationPersistenceService cc =
+          ClusterStartupRule.getLocator().getConfigurationPersistenceService();
+      CacheConfig config = cc.getCacheConfig("cluster");
+
+      List<RegionConfig> regions = config.getRegions();
+      assertThat(regions).isNotEmpty();
+      assertThat(regions).hasSize(2);
+
+      List<String> regionNames = Arrays.asList(regionName, regionFromTemplateName);
+      regionNames.forEach(name -> {
+        RegionConfig regionConfig = CacheElement.findElement(config.getRegions(), name);
+        assertThat(regionConfig).isNotNull();
+        assertThat(regionConfig.getName()).isEqualTo(name);
+
+        RegionAttributesType regionAttributes = regionConfig.getRegionAttributes().get(0);
+        RegionAttributesType.PartitionAttributes partitionAttributes =
+            regionAttributes.getPartitionAttributes();
+
+        assertThat(partitionAttributes.getRecoveryDelay())
+            .describedAs("Recovery delay should be 1 for region " + name)
+            .isEqualTo("1");
+        assertThat(partitionAttributes.getLocalMaxMemory())
+            .describedAs("Local max memory should be 1000 for region " + name)
+            .isEqualTo("1000");
+        assertThat(partitionAttributes.getRedundantCopies())
+            .describedAs("Redundant copies should be 1 for region " + name)
+            .isEqualTo("1");
+        assertThat(partitionAttributes.getStartupRecoveryDelay())
+            .describedAs("Startup recovery delay should be 1 for region " + name)
+            .isEqualTo("1");
+        assertThat(partitionAttributes.getTotalMaxMemory())
+            .describedAs("Total max memory should be 100 for region " + name)
+            .isEqualTo("100");
+        assertThat(partitionAttributes.getTotalNumBuckets())
+            .describedAs("Total num buckets should be 1 for region " + name)
+            .isEqualTo("1");
+      });
+    });
+  }
+
+  @Test
+  public void createRegionPersistsPartitionResolver() {
+    String regionName = testName.getMethodName();
+
+    gfsh.executeAndAssertThat("create region"
+        + " --name=" + regionName
+        + " --type=PARTITION"
+        + " --partition-resolver=" + DummyPartitionResolver.class.getName()).statusIsSuccess();
+
+    locator.invoke(() -> {
+      InternalConfigurationPersistenceService cc =
+          ClusterStartupRule.getLocator().getConfigurationPersistenceService();
+      CacheConfig config = cc.getCacheConfig("cluster");
+
+      List<RegionConfig> regions = config.getRegions();
+      assertThat(regions).isNotEmpty();
+      assertThat(regions).hasSize(1);
+
+      RegionConfig regionConfig = CacheElement.findElement(config.getRegions(), regionName);
+      assertThat(regionConfig).isNotNull();
+      assertThat(regionConfig.getName()).isEqualTo(regionName);
+
+      RegionAttributesType regionAttributes = regionConfig.getRegionAttributes().get(0);
+      RegionAttributesType.PartitionAttributes partitionAttributes =
+          regionAttributes.getPartitionAttributes();
+
+      assertThat(partitionAttributes.getPartitionResolver().getClassName())
+          .isEqualTo(DummyPartitionResolver.class.getName());
+    });
+  }
+
+  @Test
+  public void createRegionDoesNotPersistEmptyOrDefaultPartitionAttributes() {
+    String regionName = testName.getMethodName();
+    String regionFromTemplateName = regionName + "-from-template";
+
+    gfsh.executeAndAssertThat("create region"
+        + " --name=" + regionName
+        + " --type=REPLICATE").statusIsSuccess();
+
+    gfsh.executeAndAssertThat("create region"
+        + " --name=" + regionFromTemplateName
+        + " --template-region=" + regionName);
+
+    locator.invoke(() -> {
+      InternalConfigurationPersistenceService cc =
+          ClusterStartupRule.getLocator().getConfigurationPersistenceService();
+      CacheConfig config = cc.getCacheConfig("cluster");
+
+      List<RegionConfig> regions = config.getRegions();
+      assertThat(regions).isNotEmpty();
+      assertThat(regions).hasSize(2);
+
+      RegionConfig regionConfig =
+          CacheElement.findElement(config.getRegions(), regionFromTemplateName);
+      assertThat(regionConfig).isNotNull();
+      assertThat(regionConfig.getName()).isEqualTo(regionFromTemplateName);
+      assertThat(regionConfig.getRegionAttributes())
+          .describedAs("Expecting region attributes to exist")
+          .hasSize(1);
+
+      RegionAttributesType attr = regionConfig.getRegionAttributes().get(0);
+      assertThat(attr.getPartitionAttributes())
+          .describedAs("Partition attributes should be null for " + regionFromTemplateName)
+          .isNull();
+    });
+  }
+
+  @Test
+  public void createRegionDoestNotPersistEmptyOrDefaultExpirationAttributes() {
+    String regionName = testName.getMethodName();
+    gfsh.executeAndAssertThat("create region"
+        + " --name=" + regionName
+        + " --type=REPLICATE").statusIsSuccess();
+
+    locator.invoke(() -> {
+      InternalConfigurationPersistenceService cc =
+          ClusterStartupRule.getLocator().getConfigurationPersistenceService();
+      CacheConfig config = cc.getCacheConfig("cluster");
+
+      List<RegionConfig> regions = config.getRegions();
+      assertThat(regions).isNotEmpty();
+      assertThat(regions).hasSize(1);
+
+      RegionConfig regionConfig =
+          CacheElement.findElement(config.getRegions(), regionName);
+      assertThat(regionConfig).isNotNull();
+      assertThat(regionConfig.getName()).isEqualTo(regionName);
+      assertThat(regionConfig.getRegionAttributes())
+          .describedAs("Expecting region attributes to exist")
+          .hasSize(1);
+
+      RegionAttributesType attr = regionConfig.getRegionAttributes().get(0);
+      assertThat(attr.getRegionTimeToLive())
+          .describedAs("Expiration attributes should be null for " + regionName)
+          .isNull();
+      assertThat(attr.getRegionIdleTime())
+          .describedAs("Expiration attributes should be null for " + regionName)
+          .isNull();
+      assertThat(attr.getEntryIdleTime())
+          .describedAs("Expiration attributes should be null for " + regionName)
+          .isNull();
+      assertThat(attr.getEntryTimeToLive())
+          .describedAs("Expiration attributes should be null for " + regionName)
+          .isNull();
+    });
+  }
+
+  @Test
+  public void createRegionPersistsDisableCloningSetting() {
+    String regionName = testName.getMethodName();
+    String regionFromTemplateName = regionName + "-from-template";
+
+    gfsh.executeAndAssertThat("create region"
+        + " --name=" + regionName
+        + " --type=REPLICATE"
+        + " --enable-cloning=false").statusIsSuccess();
+
+    gfsh.executeAndAssertThat("create region"
+        + " --name=" + regionFromTemplateName
+        + " --template-region=" + regionName);
+
+    locator.invoke(() -> {
+      InternalConfigurationPersistenceService cc =
+          ClusterStartupRule.getLocator().getConfigurationPersistenceService();
+      CacheConfig config = cc.getCacheConfig("cluster");
+
+      List<RegionConfig> regions = config.getRegions();
+      assertThat(regions).isNotEmpty();
+      assertThat(regions).hasSize(2);
+
+      List<String> regionNames = Arrays.asList(regionName, regionFromTemplateName);
+      regionNames.forEach(name -> {
+        RegionConfig regionConfig = CacheElement.findElement(config.getRegions(), name);
+        assertThat(regionConfig).isNotNull();
+        assertThat(regionConfig.getName()).isEqualTo(name);
+        assertThat(regionConfig.getRegionAttributes())
+            .describedAs("Expecting region attributes to exist for " + name)
+            .hasSize(1);
+
+        RegionAttributesType attr = regionConfig.getRegionAttributes().get(0);
+        assertThat(attr.isCloningEnabled())
+            .describedAs("Cloning should be disabled for " + name)
+            .isFalse();
+      });
+    });
+  }
+
+  @Test
+  public void createRegionPersistsCustomExpiryClass() {
+    String regionName = testName.getMethodName();
+    gfsh.executeAndAssertThat("create region"
+        + " --name=" + regionName
+        + " --type=REPLICATE"
+        + " --enable-statistics=true"
+        + " --entry-idle-time-custom-expiry=" + DummyCustomExpiry.class.getName())
+        .statusIsSuccess();
+
+    locator.invoke(() -> {
+      InternalConfigurationPersistenceService cc =
+          ClusterStartupRule.getLocator().getConfigurationPersistenceService();
+      CacheConfig config = cc.getCacheConfig("cluster");
+
+      List<RegionConfig> regions = config.getRegions();
+      assertThat(regions).isNotEmpty();
+      assertThat(regions).hasSize(1);
+
+      RegionConfig regionConfig = CacheElement.findElement(config.getRegions(), regionName);
+      assertThat(regionConfig).isNotNull();
+      assertThat(regionConfig.getName()).isEqualTo(regionName);
+      assertThat(regionConfig.getRegionAttributes())
+          .describedAs("Expecting region attributes to exist for " + regionName)
+          .hasSize(1);
+      RegionAttributesType attr = regionConfig.getRegionAttributes().get(0);
+      assertThat(attr.getEntryIdleTime().getExpirationAttributes().getCustomExpiry().toString())
+          .describedAs("Entry expiration custom expiration should be DummyCustomExpiry")
+          .isEqualTo(DummyCustomExpiry.class.getName());
+    });
+  }
+
+  @Test
+  public void createRegionPersistsImplicitTemplateAttributes() {
+    String regionName = testName.getMethodName();
+    gfsh.executeAndAssertThat("create region"
+        + " --name=" + regionName
+        + " --type=PARTITION")
+        .statusIsSuccess();
+
+    locator.invoke(() -> {
+      InternalConfigurationPersistenceService cc =
+          ClusterStartupRule.getLocator().getConfigurationPersistenceService();
+      CacheConfig config = cc.getCacheConfig("cluster");
+
+      List<RegionConfig> regions = config.getRegions();
+      assertThat(regions).isNotEmpty();
+      assertThat(regions).hasSize(1);
+
+      RegionConfig regionConfig = CacheElement.findElement(config.getRegions(), regionName);
+      assertThat(regionConfig).isNotNull();
+      assertThat(regionConfig.getName()).isEqualTo(regionName);
+      assertThat(regionConfig.getRegionAttributes())
+          .describedAs("Expecting region attributes to exist for " + regionName)
+          .hasSize(1);
+
+      RegionAttributesType attr = regionConfig.getRegionAttributes().get(0);
+      assertThat(attr.getDataPolicy())
+          .describedAs("Data policy for partitioned region should be persisted correctly")
+          .isEqualTo(RegionAttributesDataPolicy.PARTITION);
+    });
+  }
+}
diff --git a/geode-core/src/distributedTest/java/org/apache/geode/management/internal/configuration/ImportOldClusterConfigDUnitTest.java b/geode-core/src/distributedTest/java/org/apache/geode/management/internal/configuration/ImportOldClusterConfigDUnitTest.java
index 287ed83..e6974a2 100644
--- a/geode-core/src/distributedTest/java/org/apache/geode/management/internal/configuration/ImportOldClusterConfigDUnitTest.java
+++ b/geode-core/src/distributedTest/java/org/apache/geode/management/internal/configuration/ImportOldClusterConfigDUnitTest.java
@@ -62,7 +62,7 @@ public class ImportOldClusterConfigDUnitTest {
   }
 
   @Test
-  public void importOldConfigThenCreateRegionCorruptsCachXml() throws Exception {
+  public void importOldConfigThenCreateRegionCorruptsCacheXml() throws Exception {
     locator = lsRule.startLocatorVM(0);
 
     gfsh.connectAndVerify(locator);
diff --git a/geode-core/src/main/java/org/apache/geode/cache/DataPolicy.java b/geode-core/src/main/java/org/apache/geode/cache/DataPolicy.java
index 5ba6e53..06221fd 100644
--- a/geode-core/src/main/java/org/apache/geode/cache/DataPolicy.java
+++ b/geode-core/src/main/java/org/apache/geode/cache/DataPolicy.java
@@ -18,6 +18,8 @@ package org.apache.geode.cache;
 
 import java.io.ObjectStreamException;
 
+import org.apache.geode.cache.configuration.RegionAttributesDataPolicy;
+
 
 /**
  * Enumerated type for region data policy. The data policy specifies how this local cache will
@@ -289,4 +291,9 @@ public class DataPolicy implements java.io.Serializable {
   public String toString() {
     return this.name;
   }
+
+  public RegionAttributesDataPolicy toConfigType() {
+    String configName = this.name.toLowerCase().replace("_", "-");
+    return RegionAttributesDataPolicy.fromValue(configName);
+  }
 }
diff --git a/geode-core/src/main/java/org/apache/geode/cache/EvictionAttributes.java b/geode-core/src/main/java/org/apache/geode/cache/EvictionAttributes.java
index 66a1bb7..b333b2e 100644
--- a/geode-core/src/main/java/org/apache/geode/cache/EvictionAttributes.java
+++ b/geode-core/src/main/java/org/apache/geode/cache/EvictionAttributes.java
@@ -16,6 +16,8 @@
 package org.apache.geode.cache;
 
 import org.apache.geode.DataSerializable;
+import org.apache.geode.cache.configuration.EnumActionDestroyOverflow;
+import org.apache.geode.cache.configuration.RegionAttributesType;
 import org.apache.geode.cache.control.ResourceManager;
 import org.apache.geode.cache.util.ObjectSizer;
 import org.apache.geode.internal.cache.EvictionAttributesImpl;
@@ -505,4 +507,41 @@ public abstract class EvictionAttributes implements DataSerializable {
         .setAction(evictionAction).setMaximum(maximumMegabytes).setObjectSizer(null);
   }
 
+  public RegionAttributesType.EvictionAttributes convertToConfigEvictionAttributes() {
+    RegionAttributesType.EvictionAttributes configAttributes =
+        new RegionAttributesType.EvictionAttributes();
+    EnumActionDestroyOverflow action = EnumActionDestroyOverflow.fromValue(this.getAction()
+        .toString());
+    EvictionAlgorithm algorithm = getAlgorithm();
+    String objectSizerClass = getObjectSizer().getClass().toString();
+    Integer maximum = getMaximum();
+
+    if (algorithm.isLRUHeap()) {
+      RegionAttributesType.EvictionAttributes.LruHeapPercentage heapPercentage =
+          new RegionAttributesType.EvictionAttributes.LruHeapPercentage();
+      heapPercentage.setAction(action);
+      heapPercentage.setClassName(objectSizerClass);
+      configAttributes.setLruHeapPercentage(heapPercentage);
+    } else if (algorithm.isLRUMemory()) {
+      RegionAttributesType.EvictionAttributes.LruMemorySize memorySize =
+          new RegionAttributesType.EvictionAttributes.LruMemorySize();
+      memorySize.setAction(action);
+      memorySize.setClassName(objectSizerClass);
+      memorySize.setMaximum(maximum.toString());
+      configAttributes.setLruMemorySize(memorySize);
+    } else {
+      RegionAttributesType.EvictionAttributes.LruEntryCount entryCount =
+          new RegionAttributesType.EvictionAttributes.LruEntryCount();
+      entryCount.setAction(action);
+      entryCount.setMaximum(maximum.toString());
+      configAttributes.setLruEntryCount(entryCount);
+    }
+
+    return configAttributes;
+  }
+
+  public boolean isEmpty() {
+    return getAction() == EvictionAction.NONE && getAlgorithm() == EvictionAlgorithm.NONE;
+  }
+
 }
diff --git a/geode-core/src/main/java/org/apache/geode/cache/ExpirationAction.java b/geode-core/src/main/java/org/apache/geode/cache/ExpirationAction.java
index ea7df84..0b66ddc 100644
--- a/geode-core/src/main/java/org/apache/geode/cache/ExpirationAction.java
+++ b/geode-core/src/main/java/org/apache/geode/cache/ExpirationAction.java
@@ -120,6 +120,21 @@ public class ExpirationAction implements Serializable {
     return this.name;
   }
 
+  public String toXmlString() {
+    switch (this.name) {
+      case "INVALIDATE":
+        return "invalidate";
+      case "DESTROY":
+        return "destroy";
+      case "LOCAL_DESTROY":
+        return "local-destroy";
+      case "LOCAL_INVALIDATE":
+        return "local-invalidate";
+      default:
+        return null;
+    }
+  }
+
   // The 4 declarations below are necessary for serialization
   private static int nextOrdinal = 0;
   public final int ordinal = nextOrdinal++;
diff --git a/geode-core/src/main/java/org/apache/geode/cache/ExpirationAttributes.java b/geode-core/src/main/java/org/apache/geode/cache/ExpirationAttributes.java
index 8cf2fb0..ebd08ee 100644
--- a/geode-core/src/main/java/org/apache/geode/cache/ExpirationAttributes.java
+++ b/geode-core/src/main/java/org/apache/geode/cache/ExpirationAttributes.java
@@ -21,6 +21,7 @@ import java.io.IOException;
 
 import org.apache.geode.DataSerializable;
 import org.apache.geode.DataSerializer;
+import org.apache.geode.cache.configuration.ExpirationAttributesType;
 import org.apache.geode.internal.InternalDataSerializer;
 
 /**
@@ -149,7 +150,7 @@ public class ExpirationAttributes implements DataSerializable {
 
   public void fromData(DataInput in) throws IOException, ClassNotFoundException {
     this.timeout = in.readInt();
-    this.action = (ExpirationAction) DataSerializer.readObject(in);
+    this.action = DataSerializer.readObject(in);
 
   }
 
@@ -157,4 +158,17 @@ public class ExpirationAttributes implements DataSerializable {
     out.writeInt(this.timeout);
     DataSerializer.writeObject(this.action, out);
   }
+
+  public ExpirationAttributesType toConfigType() {
+    ExpirationAttributesType t = new ExpirationAttributesType();
+    t.setTimeout(Integer.toString(this.timeout));
+    t.setAction(this.action.toXmlString());
+
+    return t;
+  }
+
+  public boolean isDefault() {
+    return (this.action == null || this.action == ExpirationAction.INVALIDATE)
+        && (this.timeout == 0);
+  }
 }
diff --git a/geode-core/src/main/java/org/apache/geode/cache/PartitionAttributes.java b/geode-core/src/main/java/org/apache/geode/cache/PartitionAttributes.java
index d137fa3..2cab775 100644
--- a/geode-core/src/main/java/org/apache/geode/cache/PartitionAttributes.java
+++ b/geode-core/src/main/java/org/apache/geode/cache/PartitionAttributes.java
@@ -18,6 +18,8 @@ package org.apache.geode.cache;
 import java.util.List;
 import java.util.Properties;
 
+import org.apache.geode.cache.configuration.DeclarableType;
+import org.apache.geode.cache.configuration.RegionAttributesType;
 import org.apache.geode.cache.partition.PartitionListener;
 
 /**
@@ -153,4 +155,21 @@ public interface PartitionAttributes<K, V> {
    */
   List<FixedPartitionAttributes> getFixedPartitionAttributes();
 
+  default RegionAttributesType.PartitionAttributes convertToConfigPartitionAttributes() {
+    RegionAttributesType.PartitionAttributes configAttributes =
+        new RegionAttributesType.PartitionAttributes();
+    configAttributes.setColocatedWith(getColocatedWith());
+    configAttributes.setLocalMaxMemory(Integer.toString(getLocalMaxMemory()));
+    if (getPartitionResolver() != null) {
+      configAttributes.setPartitionResolver(new DeclarableType(getPartitionResolver().getName()));
+    }
+    configAttributes.setRecoveryDelay(Long.toString(getRecoveryDelay()));
+    configAttributes.setStartupRecoveryDelay(Long.toString(getStartupRecoveryDelay()));
+    configAttributes.setRedundantCopies(Integer.toString(getRedundantCopies()));
+    configAttributes.setTotalMaxMemory(Long.toString(getTotalMaxMemory()));
+    configAttributes.setTotalNumBuckets(Long.toString(getTotalNumBuckets()));
+
+    return configAttributes;
+  }
+
 }
diff --git a/geode-core/src/main/java/org/apache/geode/cache/configuration/RegionAttributesType.java b/geode-core/src/main/java/org/apache/geode/cache/configuration/RegionAttributesType.java
index e579879..436bd36 100644
--- a/geode-core/src/main/java/org/apache/geode/cache/configuration/RegionAttributesType.java
+++ b/geode-core/src/main/java/org/apache/geode/cache/configuration/RegionAttributesType.java
@@ -1795,6 +1795,17 @@ public class RegionAttributesType {
     @XmlElement(name = "lru-memory-size", namespace = "http://geode.apache.org/schema/cache")
     protected RegionAttributesType.EvictionAttributes.LruMemorySize lruMemorySize;
 
+    public String toStringRep() {
+      return "lru-entry-count: " +
+          this.lruEntryCount.getMaximum() + ", " +
+          this.lruEntryCount.getAction().toString() + ", " +
+          "\nlru-heap-percentage: " +
+          this.lruHeapPercentage.getAction().toString() +
+          "\nlru-memory-size: " +
+          this.lruMemorySize.getMaximum() +
+          this.lruMemorySize.getAction().toString();
+    }
+
     /**
      * Gets the value of the lruEntryCount property.
      *
diff --git a/geode-core/src/main/java/org/apache/geode/distributed/internal/InternalConfigurationPersistenceService.java b/geode-core/src/main/java/org/apache/geode/distributed/internal/InternalConfigurationPersistenceService.java
index 74aba94..c86a969 100644
--- a/geode-core/src/main/java/org/apache/geode/distributed/internal/InternalConfigurationPersistenceService.java
+++ b/geode-core/src/main/java/org/apache/geode/distributed/internal/InternalConfigurationPersistenceService.java
@@ -226,29 +226,6 @@ public class InternalConfigurationPersistenceService implements ConfigurationPer
   }
 
   /**
-   * Finds xml element in a group's xml, with the tagName that has given attribute and value
-   */
-  public Element getXmlElement(String group, String tagName, String attribute, String value)
-      throws IOException, SAXException, ParserConfigurationException {
-    if (group == null) {
-      group = "cluster";
-    }
-    Configuration config = getConfiguration(group);
-    Document document = XmlUtils.createDocumentFromXml(config.getCacheXmlContent());
-    NodeList elements = document.getElementsByTagName(tagName);
-    if (elements == null || elements.getLength() == 0) {
-      return null;
-    } else {
-      for (int i = 0; i < elements.getLength(); i++) {
-        Element eachElement = (Element) elements.item(i);
-        if (eachElement.getAttribute(attribute).equals(value))
-          return eachElement;
-      }
-    }
-    return null;
-  }
-
-  /**
    * Adds/replaces the xml entity in the shared configuration we don't need to trigger the change
    * listener for this modification, so it's ok to operate on the original configuration object
    */
diff --git a/geode-core/src/main/java/org/apache/geode/internal/config/JAXBService.java b/geode-core/src/main/java/org/apache/geode/internal/config/JAXBService.java
index 6927d2f..221e154 100644
--- a/geode-core/src/main/java/org/apache/geode/internal/config/JAXBService.java
+++ b/geode-core/src/main/java/org/apache/geode/internal/config/JAXBService.java
@@ -51,6 +51,7 @@ public class JAXBService {
       marshaller = jaxbContext.createMarshaller();
       unmarshaller = jaxbContext.createUnmarshaller();
       marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
+      marshaller.setProperty(Marshaller.JAXB_FRAGMENT, true);
 
       String schemas = Arrays.stream(xsdRootClasses).map(c -> {
         XSDRootElement element = c.getAnnotation(XSDRootElement.class);
@@ -69,7 +70,7 @@ public class JAXBService {
 
   public void validateWith(URL url) {
     SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
-    Schema schema = null;
+    Schema schema;
     try {
       schema = factory.newSchema(url);
     } catch (SAXException e) {
@@ -88,6 +89,7 @@ public class JAXBService {
   public String marshall(Object object) {
     StringWriter sw = new StringWriter();
     try {
+      sw.write("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>");
       marshaller.marshal(object, sw);
     } catch (Exception e) {
       throw new RuntimeException(e.getMessage(), e);
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 9c24efe..6d8175d 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
@@ -26,7 +26,6 @@ import org.apache.geode.cache.CacheWriter;
 import org.apache.geode.cache.CustomExpiry;
 import org.apache.geode.cache.ExpirationAction;
 import org.apache.geode.distributed.DistributedMember;
-import org.apache.geode.distributed.internal.InternalConfigurationPersistenceService;
 import org.apache.geode.internal.cache.InternalCache;
 import org.apache.geode.management.cli.CliMetaData;
 import org.apache.geode.management.cli.ConverterHint;
@@ -139,7 +138,7 @@ public class AlterRegionCommand extends InternalGfshCommand {
     XmlEntity xmlEntity = findXmlEntity(regionAlterResults);
     if (xmlEntity != null) {
       persistClusterConfiguration(result,
-          () -> ((InternalConfigurationPersistenceService) getConfigurationPersistenceService())
+          () -> getConfigurationPersistenceService()
               .addXmlEntity(xmlEntity, groups));
     }
     return result;
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 b28569a..4686f01 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
@@ -39,9 +39,12 @@ import org.apache.geode.cache.ExpirationAction;
 import org.apache.geode.cache.Region;
 import org.apache.geode.cache.RegionAttributes;
 import org.apache.geode.cache.RegionShortcut;
+import org.apache.geode.cache.configuration.CacheConfig;
+import org.apache.geode.cache.configuration.RegionConfig;
 import org.apache.geode.cache.execute.ResultCollector;
 import org.apache.geode.distributed.DistributedMember;
 import org.apache.geode.internal.cache.InternalCache;
+import org.apache.geode.internal.logging.LogService;
 import org.apache.geode.management.DistributedRegionMXBean;
 import org.apache.geode.management.DistributedSystemMXBean;
 import org.apache.geode.management.ManagementService;
@@ -50,11 +53,13 @@ import org.apache.geode.management.RegionMXBean;
 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.cli.SingleGfshCommand;
 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.domain.RegionConfigFactory;
 import org.apache.geode.management.internal.cli.exceptions.EntityExistsException;
 import org.apache.geode.management.internal.cli.functions.CliFunctionResult;
 import org.apache.geode.management.internal.cli.functions.FetchRegionAttributesFunction;
@@ -63,18 +68,18 @@ import org.apache.geode.management.internal.cli.functions.RegionCreateFunction;
 import org.apache.geode.management.internal.cli.functions.RegionFunctionArgs;
 import org.apache.geode.management.internal.cli.i18n.CliStrings;
 import org.apache.geode.management.internal.cli.result.ResultBuilder;
+import org.apache.geode.management.internal.cli.result.model.ResultModel;
 import org.apache.geode.management.internal.cli.util.RegionPath;
-import org.apache.geode.management.internal.configuration.domain.XmlEntity;
 import org.apache.geode.management.internal.security.ResourceOperation;
 import org.apache.geode.security.ResourcePermission;
 
-public class CreateRegionCommand extends InternalGfshCommand {
+public class CreateRegionCommand extends SingleGfshCommand {
   @CliCommand(value = CliStrings.CREATE_REGION, help = CliStrings.CREATE_REGION__HELP)
   @CliMetaData(relatedTopic = CliStrings.TOPIC_GEODE_REGION,
       interceptor = "org.apache.geode.management.internal.cli.commands.CreateRegionCommand$Interceptor")
   @ResourceOperation(resource = ResourcePermission.Resource.DATA,
       operation = ResourcePermission.Operation.MANAGE)
-  public Result createRegion(
+  public ResultModel createRegion(
       @CliOption(key = CliStrings.CREATE_REGION__REGION, mandatory = true,
           optionContext = ConverterHint.REGION_PATH,
           help = CliStrings.CREATE_REGION__REGION__HELP) String regionPath,
@@ -180,15 +185,13 @@ public class CreateRegionCommand extends InternalGfshCommand {
           help = CliStrings.CREATE_REGION__VALUECONSTRAINT__HELP) String valueConstraint
   // NOTICE: keep the region attributes params in alphabetical order
   ) {
-    Result result;
-
     if (regionShortcut != null && templateRegion != null) {
-      return ResultBuilder.createUserErrorResult(
+      return ResultModel.createError(
           CliStrings.CREATE_REGION__MSG__ONLY_ONE_OF_REGIONSHORTCUT_AND_USEATTRIBUESFROM_CAN_BE_SPECIFIED);
     }
 
     if (regionShortcut == null && templateRegion == null) {
-      return ResultBuilder.createUserErrorResult(
+      return ResultModel.createError(
           CliStrings.CREATE_REGION__MSG__ONE_OF_REGIONSHORTCUT_AND_USEATTRIBUTESFROM_IS_REQUIRED);
     }
 
@@ -217,6 +220,7 @@ public class CreateRegionCommand extends InternalGfshCommand {
 
       // we first make sure E and C have the compatible data policy
       if (regionShortcut.isPartition() && !existingDataPolicy.contains("PARTITION")) {
+        LogService.getLogger().info("Create region command: got EntityExists exception");
         throw new EntityExistsException("The existing region is not a partitioned region",
             ifNotExists);
       }
@@ -244,7 +248,7 @@ public class CreateRegionCommand extends InternalGfshCommand {
     String parentRegionPath = regionPathData.getParent();
     if (parentRegionPath != null && !Region.SEPARATOR.equals(parentRegionPath)) {
       if (!regionExists(cache, parentRegionPath)) {
-        return ResultBuilder.createUserErrorResult(
+        return ResultModel.createError(
             CliStrings.format(CliStrings.CREATE_REGION__MSG__PARENT_REGION_FOR_0_DOES_NOT_EXIST,
                 new Object[] {regionPath}));
       }
@@ -282,16 +286,17 @@ public class CreateRegionCommand extends InternalGfshCommand {
     RegionAttributes<?, ?> regionAttributes = null;
     if (regionShortcut != null) {
       if (!regionShortcut.name().startsWith("PARTITION") && functionArgs.hasPartitionAttributes()) {
-        return ResultBuilder.createUserErrorResult(CliStrings.format(
+        return ResultModel.createError(CliStrings.format(
             CliStrings.CREATE_REGION__MSG__OPTION_0_CAN_BE_USED_ONLY_FOR_PARTITIONEDREGION,
             functionArgs.getPartitionArgs().getUserSpecifiedPartitionAttributes()) + " "
             + CliStrings.format(CliStrings.CREATE_REGION__MSG__0_IS_NOT_A_PARITIONEDREGION,
                 regionPath));
       }
       functionArgs.setRegionShortcut(regionShortcut);
+      functionArgs.setRegionAttributes(cache.getRegionAttributes(regionShortcut.toString()));
     } else { // templateRegion != null
       if (!regionExists(cache, templateRegion)) {
-        return ResultBuilder.createUserErrorResult(CliStrings.format(
+        return ResultModel.createError(CliStrings.format(
             CliStrings.CREATE_REGION__MSG__SPECIFY_VALID_REGION_PATH_FOR_0_REGIONPATH_1_NOT_FOUND,
             CliStrings.CREATE_REGION__USEATTRIBUTESFROM, templateRegion));
       }
@@ -299,14 +304,14 @@ public class CreateRegionCommand extends InternalGfshCommand {
       RegionAttributesWrapper<?, ?> wrappedAttributes = getRegionAttributes(cache, templateRegion);
 
       if (wrappedAttributes == null) {
-        return ResultBuilder.createGemFireErrorResult(CliStrings.format(
+        return ResultModel.createError(CliStrings.format(
             CliStrings.CREATE_REGION__MSG__COULD_NOT_RETRIEVE_REGION_ATTRS_FOR_PATH_0_VERIFY_REGION_EXISTS,
             templateRegion));
       }
 
       if (wrappedAttributes.getRegionAttributes().getPartitionAttributes() == null
           && functionArgs.hasPartitionAttributes()) {
-        return ResultBuilder.createUserErrorResult(CliStrings.format(
+        return ResultModel.createError(CliStrings.format(
             CliStrings.CREATE_REGION__MSG__OPTION_0_CAN_BE_USED_ONLY_FOR_PARTITIONEDREGION,
             functionArgs.getPartitionArgs().getUserSpecifiedPartitionAttributes()) + " "
             + CliStrings.format(CliStrings.CREATE_REGION__MSG__0_IS_NOT_A_PARITIONEDREGION,
@@ -358,14 +363,14 @@ public class CreateRegionCommand extends InternalGfshCommand {
         DistributedRegionMXBean distributedRegionMXBean =
             mgmtService.getDistributedRegionMXBean(prColocatedWith);
         if (distributedRegionMXBean == null) {
-          return ResultBuilder.createUserErrorResult(CliStrings.format(
+          return ResultModel.createError(CliStrings.format(
               CliStrings.CREATE_REGION__MSG__SPECIFY_VALID_REGION_PATH_FOR_0_REGIONPATH_1_NOT_FOUND,
               CliStrings.CREATE_REGION__COLOCATEDWITH, prColocatedWith));
         }
         String regionType = distributedRegionMXBean.getRegionType();
         if (!(DataPolicy.PARTITION.toString().equals(regionType)
             || DataPolicy.PERSISTENT_PARTITION.toString().equals(regionType))) {
-          return ResultBuilder.createUserErrorResult(CliStrings.format(
+          return ResultModel.createError(CliStrings.format(
               CliStrings.CREATE_REGION__MSG__COLOCATEDWITH_REGION_0_IS_NOT_PARTITIONEDREGION,
               new Object[] {prColocatedWith}));
         }
@@ -377,14 +382,14 @@ public class CreateRegionCommand extends InternalGfshCommand {
       Set<String> existingGatewaySenders =
           Arrays.stream(dsMBean.listGatewaySenders()).collect(Collectors.toSet());
       if (existingGatewaySenders.size() == 0) {
-        return ResultBuilder
-            .createUserErrorResult(CliStrings.CREATE_REGION__MSG__NO_GATEWAYSENDERS_IN_THE_SYSTEM);
+        return ResultModel
+            .createError(CliStrings.CREATE_REGION__MSG__NO_GATEWAYSENDERS_IN_THE_SYSTEM);
       } else {
         Set<String> specifiedGatewaySenders =
             Arrays.stream(gatewaySenderIds).collect(Collectors.toSet());
         specifiedGatewaySenders.removeAll(existingGatewaySenders);
         if (!specifiedGatewaySenders.isEmpty()) {
-          return ResultBuilder.createUserErrorResult(CliStrings.format(
+          return ResultModel.createError(CliStrings.format(
               CliStrings.CREATE_REGION__MSG__SPECIFY_VALID_GATEWAYSENDER_ID_UNKNOWN_0,
               (Object[]) gatewaySenderIds));
         }
@@ -402,11 +407,11 @@ public class CreateRegionCommand extends InternalGfshCommand {
                 CliStrings.CREATE_REGION__MSG__USE_ATTRIBUTES_FROM_REGION_0_IS_NOT_WITH_PERSISTENCE,
                 new Object[] {String.valueOf(functionArgs.getTemplateRegion())});
 
-        return ResultBuilder.createUserErrorResult(message);
+        return ResultModel.createError(message);
       }
 
       if (!diskStoreExists(cache, diskStore)) {
-        return ResultBuilder.createUserErrorResult(CliStrings.format(
+        return ResultModel.createError(CliStrings.format(
             CliStrings.CREATE_REGION__MSG__SPECIFY_VALID_DISKSTORE_UNKNOWN_DISKSTORE_0,
             new Object[] {diskStore}));
       }
@@ -425,9 +430,9 @@ public class CreateRegionCommand extends InternalGfshCommand {
     // just in case we found no members with this group name
     if (membersToCreateRegionOn.isEmpty()) {
       if (groups == null || groups.length == 0) {
-        return ResultBuilder.createUserErrorResult(CliStrings.NO_MEMBERS_FOUND_MESSAGE);
+        return ResultModel.createError(CliStrings.NO_MEMBERS_FOUND_MESSAGE);
       } else {
-        return ResultBuilder.createUserErrorResult(
+        return ResultModel.createError(
             CliStrings.format(CliStrings.CREATE_REGION__MSG__GROUPS_0_ARE_INVALID,
                 (Object[]) groups));
       }
@@ -436,14 +441,70 @@ public class CreateRegionCommand extends InternalGfshCommand {
     List<CliFunctionResult> regionCreateResults = executeAndGetFunctionResult(
         RegionCreateFunction.INSTANCE, functionArgs, membersToCreateRegionOn);
 
-    result = ResultBuilder.buildResult(regionCreateResults);
-    XmlEntity xmlEntity = findXmlEntity(regionCreateResults);
-    if (xmlEntity != null) {
+    ResultModel resultModel = ResultModel.createMemberStatusResult(regionCreateResults);
+    if (resultModel.isSuccessful()) {
       verifyDistributedRegionMbean(cache, regionPath);
-      persistClusterConfiguration(result,
-          () -> getConfigurationPersistenceService().addXmlEntity(xmlEntity, groups));
+      RegionConfig config = (new RegionConfigFactory()).generate(functionArgs);
+      resultModel.setConfigObject(new CreateRegionResultConfig(config,
+          functionArgs.getRegionPath()));
+    }
+
+    return resultModel;
+  }
+
+  private class CreateRegionResultConfig {
+    RegionConfig getRegionConfig() {
+      return regionConfig;
+    }
+
+    String getFullRegionPath() {
+      return fullRegionPath;
+    }
+
+    private final RegionConfig regionConfig;
+    private final String fullRegionPath;
+
+    public CreateRegionResultConfig(RegionConfig regionConfig, String fullRegionPath) {
+      this.regionConfig = regionConfig;
+      this.fullRegionPath = fullRegionPath;
+    }
+  }
+
+  @Override
+  public boolean updateConfigForGroup(String group, CacheConfig config, Object configObject) {
+    if (configObject == null) {
+      return false;
+    }
+
+    CreateRegionResultConfig regionResultConfigObject = (CreateRegionResultConfig) configObject;
+    RegionConfig regionConfig = regionResultConfigObject.getRegionConfig();
+    String regionPath = regionResultConfigObject.getFullRegionPath();
+
+    RegionPath regionPathData = new RegionPath(regionPath);
+    if (regionPathData.getParent() == null) {
+      config.getRegions().add(regionConfig);
+      return true;
+    }
+
+    String[] regionsOnPath = regionPathData.getRegionsOnParentPath();
+    RegionConfig rootConfig = config.getRegions().stream()
+        .filter(r -> r.getName().equals(regionsOnPath[0]))
+        .findFirst()
+        .get();
+
+    RegionConfig currentConfig = rootConfig;
+    for (int i = 1; i < regionsOnPath.length; i++) {
+      final String curRegionName = regionsOnPath[i];
+      currentConfig = currentConfig.getRegions()
+          .stream()
+          .filter(r -> r.getName().equals(curRegionName))
+          .findFirst()
+          .get();
     }
-    return result;
+
+    currentConfig.getRegions().add(regionConfig);
+
+    return true;
   }
 
   boolean verifyDistributedRegionMbean(InternalCache cache, String regionName) {
@@ -655,6 +716,14 @@ public class CreateRegionCommand extends InternalGfshCommand {
             .format(CliStrings.CREATE_REGION__MSG__INVALID_COMPRESSOR, new Object[] {compressor}));
       }
 
+      Boolean cloningEnabled =
+          (Boolean) parseResult.getParamValue(CliStrings.CREATE_REGION__CLONINGENABLED);
+      if (compressor != null && cloningEnabled != null && !cloningEnabled) {
+        return ResultBuilder.createUserErrorResult(CliStrings
+            .format(CliStrings.CREATE_REGION__MSG__CANNOT_DISABLE_CLONING_WITH_COMPRESSOR,
+                new Object[] {compressor}));
+      }
+
       String diskStore = parseResult.getParamValueAsString(CliStrings.CREATE_REGION__DISKSTORE);
       if (diskStore != null) {
         String regionShortcut =
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/domain/RegionAttributeGetFunction.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/domain/RegionAttributeGetFunction.java
new file mode 100644
index 0000000..ebee2db
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/domain/RegionAttributeGetFunction.java
@@ -0,0 +1,22 @@
+/*
+ * 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 org.apache.geode.cache.configuration.RegionAttributesType;
+
+@FunctionalInterface
+public interface RegionAttributeGetFunction {
+  Object getValue(RegionAttributesType attributesType);
+}
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/domain/RegionAttributeSetFunction.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/domain/RegionAttributeSetFunction.java
new file mode 100644
index 0000000..051e815
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/domain/RegionAttributeSetFunction.java
@@ -0,0 +1,22 @@
+/*
+ * 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 org.apache.geode.cache.configuration.RegionAttributesType;
+
+@FunctionalInterface
+public interface RegionAttributeSetFunction {
+  void setAttributeValue(RegionAttributesType attributesType);
+}
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/domain/RegionConfigFactory.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/domain/RegionConfigFactory.java
new file mode 100644
index 0000000..59a01a7
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/domain/RegionConfigFactory.java
@@ -0,0 +1,331 @@
+/*
+ * 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.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+import org.apache.geode.cache.RegionAttributes;
+import org.apache.geode.cache.configuration.ClassNameType;
+import org.apache.geode.cache.configuration.DeclarableType;
+import org.apache.geode.cache.configuration.ExpirationAttributesType;
+import org.apache.geode.cache.configuration.RegionAttributesType;
+import org.apache.geode.cache.configuration.RegionConfig;
+import org.apache.geode.management.internal.cli.functions.RegionFunctionArgs;
+
+public class RegionConfigFactory {
+  public RegionConfig generate(RegionFunctionArgs args) {
+    RegionConfig regionConfig = new RegionConfig();
+    regionConfig.setName(getLeafRegion(args.getRegionPath()));
+
+    RegionAttributes<?, ?> regionAttributes = args.getRegionAttributes();
+    if (args.getKeyConstraint() != null) {
+      addAttribute(regionConfig, a -> a.setKeyConstraint(args.getKeyConstraint()));
+    }
+
+    if (args.getValueConstraint() != null) {
+      addAttribute(regionConfig, a -> a.setValueConstraint(args.getValueConstraint()));
+    }
+
+    if (args.getStatisticsEnabled() != null) {
+      addAttribute(regionConfig, a -> a.setStatisticsEnabled(args.getStatisticsEnabled()));
+    } else if (regionAttributes != null) {
+      addAttribute(regionConfig, a -> a.setStatisticsEnabled(regionAttributes
+          .getStatisticsEnabled()));
+    }
+
+    if (args.getEntryExpirationIdleTime() != null) {
+      RegionAttributesType.EntryIdleTime entryIdleTime = new RegionAttributesType.EntryIdleTime();
+      entryIdleTime.setExpirationAttributes(
+          args.getEntryExpirationIdleTime().getExpirationAttributes().toConfigType());
+      addAttribute(regionConfig, a -> a.setEntryIdleTime(entryIdleTime));
+    } else if (regionAttributes != null &&
+        regionAttributes.getEntryIdleTimeout() != null &&
+        !regionAttributes.getEntryIdleTimeout().isDefault()) {
+      RegionAttributesType.EntryIdleTime entryIdleTime = new RegionAttributesType.EntryIdleTime();
+      entryIdleTime.setExpirationAttributes(regionAttributes
+          .getEntryIdleTimeout().toConfigType());
+      addAttribute(regionConfig, a -> a.setEntryIdleTime(entryIdleTime));
+    }
+
+    if (args.getEntryIdleTimeCustomExpiry() != null) {
+      Object maybeEntryIdleAttr = getRegionAttributeValue(regionConfig, a -> a.getEntryIdleTime());
+      RegionAttributesType.EntryIdleTime entryIdleTime =
+          maybeEntryIdleAttr != null ? (RegionAttributesType.EntryIdleTime) maybeEntryIdleAttr
+              : new RegionAttributesType.EntryIdleTime();
+
+      ExpirationAttributesType expirationAttributes;
+      if (entryIdleTime.getExpirationAttributes() == null) {
+        expirationAttributes = new ExpirationAttributesType();
+        expirationAttributes.setTimeout("0");
+      } else {
+        expirationAttributes = entryIdleTime.getExpirationAttributes();
+      }
+
+      DeclarableType customExpiry = new DeclarableType();
+      customExpiry.setClassName(args.getEntryIdleTimeCustomExpiry().getClassName());
+      expirationAttributes.setCustomExpiry(customExpiry);
+      entryIdleTime.setExpirationAttributes(expirationAttributes);
+
+      if (maybeEntryIdleAttr == null) {
+        addAttribute(regionConfig, a -> a.setEntryIdleTime(entryIdleTime));
+      }
+    }
+
+    if (args.getEntryExpirationTTL() != null) {
+      RegionAttributesType.EntryTimeToLive entryExpTime =
+          new RegionAttributesType.EntryTimeToLive();
+      entryExpTime.setExpirationAttributes(
+          args.getEntryExpirationTTL().getExpirationAttributes().toConfigType());
+      addAttribute(regionConfig, a -> a.setEntryTimeToLive(entryExpTime));
+    } else if (regionAttributes != null
+        && regionAttributes.getEntryTimeToLive() != null
+        && !regionAttributes.getEntryTimeToLive().isDefault()) {
+      RegionAttributesType.EntryTimeToLive entryExpTime =
+          new RegionAttributesType.EntryTimeToLive();
+      entryExpTime.setExpirationAttributes(
+          regionAttributes.getEntryTimeToLive().toConfigType());
+      addAttribute(regionConfig, a -> a.setEntryTimeToLive(entryExpTime));
+    }
+
+    if (args.getRegionExpirationIdleTime() != null) {
+      RegionAttributesType.RegionIdleTime regionIdleTime =
+          new RegionAttributesType.RegionIdleTime();
+      regionIdleTime.setExpirationAttributes(
+          args.getRegionExpirationIdleTime().getExpirationAttributes().toConfigType());
+      addAttribute(regionConfig, a -> a.setRegionIdleTime(regionIdleTime));
+    } else if (regionAttributes != null
+        && regionAttributes.getRegionIdleTimeout() != null
+        && !regionAttributes.getRegionIdleTimeout().isDefault()) {
+      RegionAttributesType.RegionIdleTime regionIdleTime =
+          new RegionAttributesType.RegionIdleTime();
+      regionIdleTime.setExpirationAttributes(
+          regionAttributes.getRegionIdleTimeout().toConfigType());
+      addAttribute(regionConfig, a -> a.setRegionIdleTime(regionIdleTime));
+    }
+
+    if (args.getRegionExpirationTTL() != null) {
+      RegionAttributesType.RegionTimeToLive regionExpTime =
+          new RegionAttributesType.RegionTimeToLive();
+      regionExpTime.setExpirationAttributes(
+          args.getRegionExpirationTTL().getExpirationAttributes().toConfigType());
+      addAttribute(regionConfig, a -> a.setRegionTimeToLive(regionExpTime));
+    } else if (regionAttributes != null
+        && regionAttributes.getRegionTimeToLive() != null
+        && !regionAttributes.getRegionTimeToLive().isDefault()) {
+      RegionAttributesType.RegionTimeToLive regionExpTime =
+          new RegionAttributesType.RegionTimeToLive();
+      regionExpTime.setExpirationAttributes(
+          regionAttributes.getRegionTimeToLive().toConfigType());
+      addAttribute(regionConfig, a -> a.setRegionTimeToLive(regionExpTime));
+    }
+
+    if (args.getEntryTTLCustomExpiry() != null) {
+      Object maybeEntryTTLAttr = getRegionAttributeValue(regionConfig, a -> a.getEntryTimeToLive());
+      RegionAttributesType.EntryTimeToLive entryTimeToLive =
+          maybeEntryTTLAttr != null ? (RegionAttributesType.EntryTimeToLive) maybeEntryTTLAttr
+              : new RegionAttributesType.EntryTimeToLive();
+
+      ExpirationAttributesType expirationAttributes;
+      if (entryTimeToLive.getExpirationAttributes() == null) {
+        expirationAttributes = new ExpirationAttributesType();
+        expirationAttributes.setTimeout("0");
+      } else {
+        expirationAttributes = entryTimeToLive.getExpirationAttributes();
+      }
+
+      DeclarableType customExpiry = new DeclarableType();
+      customExpiry.setClassName(args.getEntryTTLCustomExpiry().getClassName());
+      expirationAttributes.setCustomExpiry(customExpiry);
+      entryTimeToLive.setExpirationAttributes(expirationAttributes);
+
+      if (maybeEntryTTLAttr == null) {
+        addAttribute(regionConfig, a -> a.setEntryTimeToLive(entryTimeToLive));
+      }
+    }
+
+    if (args.getDiskStore() != null) {
+      addAttribute(regionConfig, a -> a.setDiskStoreName(args.getDiskStore()));
+    } else if (regionAttributes != null) {
+      addAttribute(regionConfig, a -> a.setDiskStoreName(regionAttributes.getDiskStoreName()));
+    }
+
+    if (args.getDiskSynchronous() != null) {
+      addAttribute(regionConfig, a -> a.setDiskSynchronous(args.getDiskSynchronous()));
+    } else if (regionAttributes != null) {
+      addAttribute(regionConfig, a -> a.setDiskSynchronous(regionAttributes.isDiskSynchronous()));
+    }
+
+    if (args.getEnableAsyncConflation() != null) {
+      addAttribute(regionConfig, a -> a.setEnableAsyncConflation(args.getEnableAsyncConflation()));
+    } else if (regionAttributes != null) {
+      addAttribute(regionConfig, a -> a.setEnableAsyncConflation(regionAttributes
+          .getEnableAsyncConflation()));
+    }
+
+    if (args.getEnableSubscriptionConflation() != null) {
+      addAttribute(regionConfig,
+          a -> a.setEnableSubscriptionConflation(args.getEnableSubscriptionConflation()));
+    } else if (regionAttributes != null) {
+      addAttribute(regionConfig, a -> a.setEnableSubscriptionConflation(regionAttributes
+          .getEnableSubscriptionConflation()));
+    }
+
+    if (args.getConcurrencyChecksEnabled() != null) {
+      addAttribute(regionConfig, a -> a.setConcurrencyChecksEnabled(
+          args.getConcurrencyChecksEnabled()));
+    } else if (regionAttributes != null) {
+      addAttribute(regionConfig, a -> a.setConcurrencyChecksEnabled(regionAttributes
+          .getConcurrencyChecksEnabled()));
+    }
+
+    if (args.getCloningEnabled() != null) {
+      addAttribute(regionConfig, a -> a.setCloningEnabled(args.getCloningEnabled()));
+    } else if (regionAttributes != null) {
+      addAttribute(regionConfig, a -> a.setCloningEnabled(regionAttributes
+          .getCloningEnabled()));
+    }
+
+    if (args.getOffHeap() != null) {
+      addAttribute(regionConfig, a -> a.setOffHeap(args.getOffHeap()));
+    } else if (regionAttributes != null) {
+      addAttribute(regionConfig, a -> a.setOffHeap(regionAttributes.getOffHeap()));
+    }
+
+    if (args.getMcastEnabled() != null) {
+      addAttribute(regionConfig, a -> a.setMulticastEnabled(args.getMcastEnabled()));
+    } else if (regionAttributes != null) {
+      addAttribute(regionConfig, a -> a.setMulticastEnabled(regionAttributes
+          .getMulticastEnabled()));
+    }
+
+    if (args.getPartitionArgs() != null) {
+      RegionAttributesType.PartitionAttributes partitionAttributes =
+          new RegionAttributesType.PartitionAttributes();
+      RegionFunctionArgs.PartitionArgs partitionArgs = args.getPartitionArgs();
+      partitionAttributes.setColocatedWith(partitionArgs.getPrColocatedWith());
+      partitionAttributes.setLocalMaxMemory(int2string(partitionArgs.getPrLocalMaxMemory()));
+      partitionAttributes.setRecoveryDelay(long2string(partitionArgs.getPrRecoveryDelay()));
+      partitionAttributes.setRedundantCopies(int2string(partitionArgs.getPrRedundantCopies()));
+      partitionAttributes
+          .setStartupRecoveryDelay(long2string(partitionArgs.getPrStartupRecoveryDelay()));
+      partitionAttributes.setTotalMaxMemory(long2string(partitionArgs.getPrTotalMaxMemory()));
+      partitionAttributes.setTotalNumBuckets(int2string(partitionArgs.getPrTotalNumBuckets()));
+
+      if (partitionArgs.getPartitionResolver() != null) {
+        DeclarableType partitionResolverType = new DeclarableType();
+        partitionResolverType.setClassName(partitionArgs.getPartitionResolver());
+        partitionAttributes.setPartitionResolver(partitionResolverType);
+      }
+
+      addAttribute(regionConfig, a -> a.setPartitionAttributes(partitionAttributes));
+    } else if (regionAttributes != null && regionAttributes.getPartitionAttributes() != null) {
+      addAttribute(regionConfig, a -> a.setPartitionAttributes(
+          regionAttributes.getPartitionAttributes().convertToConfigPartitionAttributes()));
+    }
+
+    if (args.getGatewaySenderIds() != null && !args.getGatewaySenderIds().isEmpty()) {
+      addAttribute(regionConfig, a -> a.setGatewaySenderIds(String.join(",",
+          args.getGatewaySenderIds())));
+    }
+
+    if (args.getEvictionAttributes() != null) {
+      addAttribute(regionConfig, a -> a.setEvictionAttributes(
+          args.getEvictionAttributes().convertToConfigEvictionAttributes()));
+    } else if (regionAttributes != null &&
+        regionAttributes.getEvictionAttributes() != null &&
+        !regionAttributes.getEvictionAttributes().isEmpty()) {
+      addAttribute(regionConfig, a -> a.setEvictionAttributes(
+          regionAttributes.getEvictionAttributes().convertToConfigEvictionAttributes()));
+    }
+
+    if (args.getAsyncEventQueueIds() != null && !args.getAsyncEventQueueIds().isEmpty()) {
+      addAttribute(regionConfig,
+          a -> a.setAsyncEventQueueIds(String.join(",", args.getAsyncEventQueueIds())));
+    }
+
+    if (args.getCacheListeners() != null && !args.getCacheListeners().isEmpty()) {
+      addAttribute(regionConfig, a -> a.getCacheListeners().addAll(
+          args.getCacheListeners().stream().map(l -> {
+            DeclarableType declarableType = new DeclarableType();
+            declarableType.setClassName(l.getClassName());
+            return declarableType;
+          }).collect(Collectors.toList())));
+    }
+
+    if (args.getCacheLoader() != null) {
+      DeclarableType declarableType = new DeclarableType();
+      declarableType.setClassName(args.getCacheLoader().getClassName());
+      addAttribute(regionConfig, a -> a.setCacheLoader(declarableType));
+    }
+
+    if (args.getCacheWriter() != null) {
+      DeclarableType declarableType = new DeclarableType();
+      declarableType.setClassName(args.getCacheWriter().getClassName());
+      addAttribute(regionConfig, a -> a.setCacheWriter(declarableType));
+    }
+
+    if (args.getCompressor() != null) {
+      addAttribute(regionConfig, a -> a.setCompressor(new ClassNameType(args.getCompressor())));
+      addAttribute(regionConfig, a -> a.setCloningEnabled(true));
+    }
+
+    if (args.getConcurrencyLevel() != null) {
+      addAttribute(regionConfig, a -> a.setConcurrencyLevel(args.getConcurrencyLevel().toString()));
+    } else if (regionAttributes != null) {
+      addAttribute(regionConfig, a -> a.setConcurrencyLevel(Integer.toString(
+          regionAttributes.getConcurrencyLevel())));
+    }
+
+    if (regionAttributes != null && regionAttributes.getDataPolicy() != null) {
+      addAttribute(regionConfig,
+          a -> a.setDataPolicy(regionAttributes.getDataPolicy().toConfigType()));
+    }
+
+    return regionConfig;
+  }
+
+  private String int2string(Integer i) {
+    return Optional.ofNullable(i).map(j -> j.toString()).orElse(null);
+  }
+
+  private String long2string(Long i) {
+    return Optional.ofNullable(i).map(j -> j.toString()).orElse(null);
+  }
+
+  private String getLeafRegion(String fullPath) {
+    String regionPath = fullPath;
+    String[] regions = regionPath.split("/");
+
+    return regions[regions.length - 1];
+  }
+
+  private void addAttribute(RegionConfig config, RegionAttributeSetFunction func) {
+    final List<RegionAttributesType> regionAttributes = config.getRegionAttributes();
+    if (regionAttributes.isEmpty()) {
+      regionAttributes.add(new RegionAttributesType());
+    }
+
+    func.setAttributeValue(regionAttributes.get(0));
+  }
+
+  private Object getRegionAttributeValue(RegionConfig config, RegionAttributeGetFunction function) {
+    return config.getRegionAttributes().stream()
+        .findFirst()
+        .map(a -> function.getValue(a))
+        .orElse(null);
+  }
+}
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 fe53185..d568041 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
@@ -111,8 +111,8 @@ public class RegionAlterFunction implements InternalFunction {
 
     AttributesMutator mutator = region.getAttributesMutator();
 
-    if (regionAlterArgs.isCloningEnabled() != null) {
-      mutator.setCloningEnabled(regionAlterArgs.isCloningEnabled());
+    if (regionAlterArgs.getCloningEnabled() != null) {
+      mutator.setCloningEnabled(regionAlterArgs.getCloningEnabled());
       if (logger.isDebugEnabled()) {
         logger.debug("Region successfully altered - cloning");
       }
@@ -128,7 +128,7 @@ public class RegionAlterFunction implements InternalFunction {
     // Alter expiration attributes
     final RegionFunctionArgs.ExpirationAttrs newEntryExpirationIdleTime =
         regionAlterArgs.getEntryExpirationIdleTime();
-    if (newEntryExpirationIdleTime.isTimeOrActionSet()) {
+    if (newEntryExpirationIdleTime != null && newEntryExpirationIdleTime.isTimeOrActionSet()) {
       mutator.setEntryIdleTimeout(
           newEntryExpirationIdleTime.getExpirationAttributes(region.getEntryIdleTimeout()));
       if (logger.isDebugEnabled()) {
@@ -138,7 +138,7 @@ public class RegionAlterFunction implements InternalFunction {
 
     final RegionFunctionArgs.ExpirationAttrs newEntryExpirationTTL =
         regionAlterArgs.getEntryExpirationTTL();
-    if (newEntryExpirationTTL.isTimeOrActionSet()) {
+    if (newEntryExpirationTTL != null && newEntryExpirationTTL.isTimeOrActionSet()) {
       mutator.setEntryTimeToLive(
           newEntryExpirationTTL.getExpirationAttributes(region.getEntryTimeToLive()));
       if (logger.isDebugEnabled()) {
@@ -167,7 +167,7 @@ public class RegionAlterFunction implements InternalFunction {
 
     final RegionFunctionArgs.ExpirationAttrs newRegionExpirationIdleTime =
         regionAlterArgs.getRegionExpirationIdleTime();
-    if (newRegionExpirationIdleTime.isTimeOrActionSet()) {
+    if (newRegionExpirationIdleTime != null && newRegionExpirationIdleTime.isTimeOrActionSet()) {
       mutator.setRegionIdleTimeout(
           newRegionExpirationIdleTime.getExpirationAttributes(region.getRegionIdleTimeout()));
       if (logger.isDebugEnabled()) {
@@ -177,7 +177,7 @@ public class RegionAlterFunction implements InternalFunction {
 
     final RegionFunctionArgs.ExpirationAttrs newRegionExpirationTTL =
         regionAlterArgs.getRegionExpirationTTL();
-    if (newRegionExpirationTTL.isTimeOrActionSet()) {
+    if (newRegionExpirationTTL != null && newRegionExpirationTTL.isTimeOrActionSet()) {
       mutator.setRegionTimeToLive(
           newRegionExpirationTTL.getExpirationAttributes(region.getRegionTimeToLive()));
       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 26ca760..353ee30 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
@@ -16,6 +16,7 @@ package org.apache.geode.management.internal.cli.functions;
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Optional;
 import java.util.Set;
 
 import org.apache.commons.lang3.StringUtils;
@@ -84,21 +85,22 @@ public class RegionCreateFunction implements InternalFunction {
     if (regionCreateArgs.isIfNotExists()) {
       Region<Object, Object> region = cache.getRegion(regionCreateArgs.getRegionPath());
       if (region != null) {
-        resultSender.lastResult(new CliFunctionResult(memberNameOrId, true,
-            CliStrings.format(
-                CliStrings.CREATE_REGION__MSG__SKIPPING_0_REGION_PATH_1_ALREADY_EXISTS,
-                memberNameOrId, regionCreateArgs.getRegionPath())));
+        resultSender
+            .lastResult(new CliFunctionResult(memberNameOrId, CliFunctionResult.StatusState.OK,
+                CliStrings.format(
+                    CliStrings.CREATE_REGION__MSG__SKIPPING_0_REGION_PATH_1_ALREADY_EXISTS,
+                    memberNameOrId, regionCreateArgs.getRegionPath())));
         return;
       }
     }
 
     try {
       Region<?, ?> createdRegion = createRegion(cache, regionCreateArgs);
-      XmlEntity xmlEntity = getXmlEntityForRegion(createdRegion);
 
-      resultSender.lastResult(new CliFunctionResult(memberNameOrId, xmlEntity,
-          CliStrings.format(CliStrings.CREATE_REGION__MSG__REGION_0_CREATED_ON_1,
-              createdRegion.getFullPath(), memberNameOrId)));
+      resultSender
+          .lastResult(new CliFunctionResult(memberNameOrId, CliFunctionResult.StatusState.OK,
+              CliStrings.format(CliStrings.CREATE_REGION__MSG__REGION_0_CREATED_ON_1,
+                  createdRegion.getFullPath(), memberNameOrId)));
     } catch (IllegalStateException e) {
       String exceptionMsg = e.getMessage();
       String localizedString =
@@ -154,18 +156,9 @@ public class RegionCreateFunction implements InternalFunction {
     final RegionShortcut regionShortcut = regionCreateArgs.getRegionShortcut();
 
     // create the region factory using the arguments
-    boolean isPartitioned = false;
-    RegionFactory<K, V> factory = null;
-    RegionAttributes<K, V> regionAttributes = null;
-    if (regionShortcut != null) {
-      regionAttributes = cache.getRegionAttributes(regionShortcut.toString());
-      regionCreateArgs.setRegionAttributes(regionAttributes);
-    } else {
-      regionAttributes = regionCreateArgs.getRegionAttributes();
-    }
-
-    isPartitioned = regionAttributes.getPartitionAttributes() != null;
-    factory = cache.createRegionFactory(regionAttributes);
+    RegionAttributes<K, V> regionAttributes = regionCreateArgs.getRegionAttributes();
+    boolean isPartitioned = regionAttributes.getPartitionAttributes() != null;
+    RegionFactory<K, V> factory = cache.createRegionFactory(regionAttributes);
 
     if (isPartitioned) {
       PartitionAttributes<K, V> partitionAttributes =
@@ -197,7 +190,7 @@ public class RegionCreateFunction implements InternalFunction {
     // Expiration attributes
     final RegionFunctionArgs.ExpirationAttrs entryExpirationIdleTime =
         regionCreateArgs.getEntryExpirationIdleTime();
-    if (entryExpirationIdleTime.isTimeOrActionSet()) {
+    if (entryExpirationIdleTime != null && entryExpirationIdleTime.isTimeOrActionSet()) {
       factory.setEntryIdleTimeout(entryExpirationIdleTime.getExpirationAttributes());
     }
 
@@ -213,21 +206,23 @@ public class RegionCreateFunction implements InternalFunction {
 
     final RegionFunctionArgs.ExpirationAttrs entryExpirationTTL =
         regionCreateArgs.getEntryExpirationTTL();
-    if (entryExpirationTTL.isTimeOrActionSet()) {
+    if (entryExpirationTTL != null && entryExpirationTTL.isTimeOrActionSet()) {
       factory.setEntryTimeToLive(entryExpirationTTL.getExpirationAttributes());
     }
     final RegionFunctionArgs.ExpirationAttrs regionExpirationIdleTime =
         regionCreateArgs.getRegionExpirationIdleTime();
-    if (regionExpirationIdleTime.isTimeOrActionSet()) {
+    if (regionExpirationIdleTime != null && regionExpirationIdleTime.isTimeOrActionSet()) {
       factory.setRegionIdleTimeout(regionExpirationIdleTime.getExpirationAttributes());
     }
     final RegionFunctionArgs.ExpirationAttrs regionExpirationTTL =
         regionCreateArgs.getRegionExpirationTTL();
-    if (regionExpirationTTL.isTimeOrActionSet()) {
+    if (regionExpirationTTL != null && regionExpirationTTL.isTimeOrActionSet()) {
       factory.setRegionTimeToLive(regionExpirationTTL.getExpirationAttributes());
     }
 
-    EvictionAttributes evictionAttributes = regionCreateArgs.getEvictionAttributes();
+    EvictionAttributes evictionAttributes = Optional
+        .ofNullable(regionCreateArgs.getEvictionAttributes())
+        .map(a -> a.convertToEvictionAttributes()).orElse(null);
     if (evictionAttributes != null) {
       ObjectSizer sizer = evictionAttributes.getObjectSizer();
       if (sizer != null && !(sizer instanceof Declarable)) {
@@ -243,24 +238,24 @@ public class RegionCreateFunction implements InternalFunction {
       factory.setDiskStoreName(diskStore);
     }
 
-    if (regionCreateArgs.isDiskSynchronous() != null) {
-      factory.setDiskSynchronous(regionCreateArgs.isDiskSynchronous());
+    if (regionCreateArgs.getDiskSynchronous() != null) {
+      factory.setDiskSynchronous(regionCreateArgs.getDiskSynchronous());
     }
 
-    if (regionCreateArgs.isOffHeap() != null) {
-      factory.setOffHeap(regionCreateArgs.isOffHeap());
+    if (regionCreateArgs.getOffHeap() != null) {
+      factory.setOffHeap(regionCreateArgs.getOffHeap());
     }
 
-    if (regionCreateArgs.isStatisticsEnabled() != null) {
-      factory.setStatisticsEnabled(regionCreateArgs.isStatisticsEnabled());
+    if (regionCreateArgs.getStatisticsEnabled() != null) {
+      factory.setStatisticsEnabled(regionCreateArgs.getStatisticsEnabled());
     }
 
-    if (regionCreateArgs.isEnableAsyncConflation() != null) {
-      factory.setEnableAsyncConflation(regionCreateArgs.isEnableAsyncConflation());
+    if (regionCreateArgs.getEnableAsyncConflation() != null) {
+      factory.setEnableAsyncConflation(regionCreateArgs.getEnableAsyncConflation());
     }
 
-    if (regionCreateArgs.isEnableSubscriptionConflation() != null) {
-      factory.setEnableSubscriptionConflation(regionCreateArgs.isEnableSubscriptionConflation());
+    if (regionCreateArgs.getEnableSubscriptionConflation() != null) {
+      factory.setEnableSubscriptionConflation(regionCreateArgs.getEnableSubscriptionConflation());
     }
 
     // Gateway Sender Ids
@@ -279,20 +274,20 @@ public class RegionCreateFunction implements InternalFunction {
       }
     }
 
-    if (regionCreateArgs.isConcurrencyChecksEnabled() != null) {
-      factory.setConcurrencyChecksEnabled(regionCreateArgs.isConcurrencyChecksEnabled());
+    if (regionCreateArgs.getConcurrencyChecksEnabled() != null) {
+      factory.setConcurrencyChecksEnabled(regionCreateArgs.getConcurrencyChecksEnabled());
     }
 
     if (regionCreateArgs.getConcurrencyLevel() != null) {
       factory.setConcurrencyLevel(regionCreateArgs.getConcurrencyLevel());
     }
 
-    if (regionCreateArgs.isCloningEnabled() != null) {
-      factory.setCloningEnabled(regionCreateArgs.isCloningEnabled());
+    if (regionCreateArgs.getCloningEnabled() != null) {
+      factory.setCloningEnabled(regionCreateArgs.getCloningEnabled());
     }
 
-    if (regionCreateArgs.isMcastEnabled() != null) {
-      factory.setMulticastEnabled(regionCreateArgs.isMcastEnabled());
+    if (regionCreateArgs.getMcastEnabled() != null) {
+      factory.setMulticastEnabled(regionCreateArgs.getMcastEnabled());
     }
 
     // Set plugins
@@ -341,9 +336,8 @@ public class RegionCreateFunction implements InternalFunction {
   @SuppressWarnings("unchecked")
   private static <K, V> PartitionAttributes<K, V> extractPartitionAttributes(Cache cache,
       RegionAttributes<K, V> regionAttributes, RegionFunctionArgs regionCreateArgs) {
-    RegionFunctionArgs.PartitionArgs partitionArgs = regionCreateArgs.getPartitionArgs();
 
-    PartitionAttributesFactory<K, V> prAttrFactory = null;
+    PartitionAttributesFactory<K, V> prAttrFactory;
 
     PartitionAttributes<K, V> partitionAttributes = regionAttributes.getPartitionAttributes();
     if (partitionAttributes != null) {
@@ -352,46 +346,49 @@ public class RegionCreateFunction implements InternalFunction {
       prAttrFactory = new PartitionAttributesFactory<>();
     }
 
-    String colocatedWith = partitionArgs.getPrColocatedWith();
-    if (colocatedWith != null) {
-      Region<Object, Object> colocatedWithRegion = cache.getRegion(colocatedWith);
-      if (colocatedWithRegion == null) {
-        throw new IllegalArgumentException(CliStrings.format(
-            CliStrings.CREATE_REGION__MSG__COLOCATEDWITH_REGION_0_DOES_NOT_EXIST, colocatedWith));
+    if (regionCreateArgs.hasPartitionAttributes()) {
+      RegionFunctionArgs.PartitionArgs partitionArgs = regionCreateArgs.getPartitionArgs();
+      String colocatedWith = partitionArgs.getPrColocatedWith();
+      if (colocatedWith != null) {
+        Region<Object, Object> colocatedWithRegion = cache.getRegion(colocatedWith);
+        if (colocatedWithRegion == null) {
+          throw new IllegalArgumentException(CliStrings.format(
+              CliStrings.CREATE_REGION__MSG__COLOCATEDWITH_REGION_0_DOES_NOT_EXIST, colocatedWith));
+        }
+        if (!colocatedWithRegion.getAttributes().getDataPolicy().withPartitioning()) {
+          throw new IllegalArgumentException(CliStrings.format(
+              CliStrings.CREATE_REGION__MSG__COLOCATEDWITH_REGION_0_IS_NOT_PARTITIONEDREGION,
+              colocatedWith));
+        }
+        prAttrFactory.setColocatedWith(colocatedWith);
       }
-      if (!colocatedWithRegion.getAttributes().getDataPolicy().withPartitioning()) {
-        throw new IllegalArgumentException(CliStrings.format(
-            CliStrings.CREATE_REGION__MSG__COLOCATEDWITH_REGION_0_IS_NOT_PARTITIONEDREGION,
-            colocatedWith));
+      if (partitionArgs.getPrLocalMaxMemory() != null) {
+        prAttrFactory.setLocalMaxMemory(partitionArgs.getPrLocalMaxMemory());
+      }
+      if (partitionArgs.getPrTotalMaxMemory() != null) {
+        prAttrFactory.setTotalMaxMemory(partitionArgs.getPrTotalMaxMemory());
+      }
+      if (partitionArgs.getPrTotalNumBuckets() != null) {
+        prAttrFactory.setTotalNumBuckets(partitionArgs.getPrTotalNumBuckets());
+      }
+      if (partitionArgs.getPrRedundantCopies() != null) {
+        prAttrFactory.setRedundantCopies(partitionArgs.getPrRedundantCopies());
+      }
+      if (partitionArgs.getPrRecoveryDelay() != null) {
+        prAttrFactory.setRecoveryDelay(partitionArgs.getPrRecoveryDelay());
+      }
+      if (partitionArgs.getPrStartupRecoveryDelay() != null) {
+        prAttrFactory.setStartupRecoveryDelay(partitionArgs.getPrStartupRecoveryDelay());
       }
-      prAttrFactory.setColocatedWith(colocatedWith);
-    }
-    if (partitionArgs.getPrLocalMaxMemory() != null) {
-      prAttrFactory.setLocalMaxMemory(partitionArgs.getPrLocalMaxMemory());
-    }
-    if (partitionArgs.getPrTotalMaxMemory() != null) {
-      prAttrFactory.setTotalMaxMemory(partitionArgs.getPrTotalMaxMemory());
-    }
-    if (partitionArgs.getPrTotalNumBuckets() != null) {
-      prAttrFactory.setTotalNumBuckets(partitionArgs.getPrTotalNumBuckets());
-    }
-    if (partitionArgs.getPrRedundantCopies() != null) {
-      prAttrFactory.setRedundantCopies(partitionArgs.getPrRedundantCopies());
-    }
-    if (partitionArgs.getPrRecoveryDelay() != null) {
-      prAttrFactory.setRecoveryDelay(partitionArgs.getPrRecoveryDelay());
-    }
-    if (partitionArgs.getPrStartupRecoveryDelay() != null) {
-      prAttrFactory.setStartupRecoveryDelay(partitionArgs.getPrStartupRecoveryDelay());
-    }
 
-    if (regionCreateArgs.getPartitionArgs().getPartitionResolver() != null) {
-      Class<PartitionResolver> partitionResolverClass =
-          forName(regionCreateArgs.getPartitionArgs().getPartitionResolver(),
-              CliStrings.CREATE_REGION__PARTITION_RESOLVER);
-      prAttrFactory
-          .setPartitionResolver((PartitionResolver<K, V>) newInstance(partitionResolverClass,
-              CliStrings.CREATE_REGION__PARTITION_RESOLVER));
+      if (regionCreateArgs.getPartitionArgs().getPartitionResolver() != null) {
+        Class<PartitionResolver> partitionResolverClass =
+            forName(regionCreateArgs.getPartitionArgs().getPartitionResolver(),
+                CliStrings.CREATE_REGION__PARTITION_RESOLVER);
+        prAttrFactory
+            .setPartitionResolver((PartitionResolver<K, V>) newInstance(partitionResolverClass,
+                CliStrings.CREATE_REGION__PARTITION_RESOLVER));
+      }
     }
     return prAttrFactory.create();
   }
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 948ba29..21d975d 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
@@ -33,6 +33,8 @@ import org.apache.geode.cache.ExpirationAction;
 import org.apache.geode.cache.ExpirationAttributes;
 import org.apache.geode.cache.RegionAttributes;
 import org.apache.geode.cache.RegionShortcut;
+import org.apache.geode.cache.configuration.EnumActionDestroyOverflow;
+import org.apache.geode.cache.configuration.RegionAttributesType;
 import org.apache.geode.cache.util.ObjectSizer;
 import org.apache.geode.internal.ClassPathLoader;
 import org.apache.geode.management.internal.cli.domain.ClassName;
@@ -80,9 +82,7 @@ public class RegionFunctionArgs implements Serializable {
   private Boolean offHeap;
   private RegionAttributes<?, ?> regionAttributes;
 
-  public RegionFunctionArgs() {
-    this.partitionArgs = new PartitionArgs();
-  }
+  public RegionFunctionArgs() {}
 
   public void setRegionPath(String regionPath) {
     this.regionPath = regionPath;
@@ -114,18 +114,34 @@ public class RegionFunctionArgs implements Serializable {
   }
 
   public void setEntryExpirationIdleTime(Integer timeout, ExpirationAction action) {
+    if (timeout == null && action == null) {
+      return;
+    }
+
     this.entryExpirationIdleTime = new ExpirationAttrs(timeout, action);
   }
 
   public void setEntryExpirationTTL(Integer timeout, ExpirationAction action) {
+    if (timeout == null && action == null) {
+      return;
+    }
+
     this.entryExpirationTTL = new ExpirationAttrs(timeout, action);
   }
 
   public void setRegionExpirationIdleTime(Integer timeout, ExpirationAction action) {
+    if (timeout == null && action == null) {
+      return;
+    }
+
     this.regionExpirationIdleTime = new ExpirationAttrs(timeout, action);
   }
 
   public void setRegionExpirationTTL(Integer timeout, ExpirationAction action) {
+    if (timeout == null && action == null) {
+      return;
+    }
+
     this.regionExpirationTTL = new ExpirationAttrs(timeout, action);
   }
 
@@ -199,6 +215,19 @@ public class RegionFunctionArgs implements Serializable {
   public void setPartitionArgs(String prColocatedWith, Integer prLocalMaxMemory,
       Long prRecoveryDelay, Integer prRedundantCopies, Long prStartupRecoveryDelay,
       Long prTotalMaxMemory, Integer prTotalNumBuckets, String partitionResolver) {
+    if (prColocatedWith == null &&
+        prLocalMaxMemory == null &&
+        prRecoveryDelay == null &&
+        prRedundantCopies == null &&
+        prStartupRecoveryDelay == null &&
+        prTotalMaxMemory == null &&
+        prTotalNumBuckets == null &&
+        partitionResolver == null) {
+      return;
+    }
+    if (partitionArgs == null) {
+      partitionArgs = new PartitionArgs();
+    }
     partitionArgs.setPrColocatedWith(prColocatedWith);
     partitionArgs.setPrLocalMaxMemory(prLocalMaxMemory);
     partitionArgs.setPrRecoveryDelay(prRecoveryDelay);
@@ -270,7 +299,7 @@ public class RegionFunctionArgs implements Serializable {
   /**
    * @return the statisticsEnabled
    */
-  public Boolean isStatisticsEnabled() {
+  public Boolean getStatisticsEnabled() {
     return this.statisticsEnabled;
   }
 
@@ -312,25 +341,25 @@ public class RegionFunctionArgs implements Serializable {
   /**
    * @return the diskSynchronous
    */
-  public Boolean isDiskSynchronous() {
+  public Boolean getDiskSynchronous() {
     return this.diskSynchronous;
   }
 
-  public Boolean isOffHeap() {
+  public Boolean getOffHeap() {
     return this.offHeap;
   }
 
   /**
    * @return the enableAsyncConflation
    */
-  public Boolean isEnableAsyncConflation() {
+  public Boolean getEnableAsyncConflation() {
     return this.enableAsyncConflation;
   }
 
   /**
    * @return the enableSubscriptionConflation
    */
-  public Boolean isEnableSubscriptionConflation() {
+  public Boolean getEnableSubscriptionConflation() {
     return this.enableSubscriptionConflation;
   }
 
@@ -381,21 +410,21 @@ public class RegionFunctionArgs implements Serializable {
   /**
    * @return the concurrencyChecksEnabled
    */
-  public Boolean isConcurrencyChecksEnabled() {
+  public Boolean getConcurrencyChecksEnabled() {
     return this.concurrencyChecksEnabled;
   }
 
   /**
    * @return the cloningEnabled
    */
-  public Boolean isCloningEnabled() {
+  public Boolean getCloningEnabled() {
     return this.cloningEnabled;
   }
 
   /**
    * @return the mcastEnabled setting
    */
-  public Boolean isMcastEnabled() {
+  public Boolean getMcastEnabled() {
     return this.mcastEnabled;
   }
 
@@ -415,7 +444,7 @@ public class RegionFunctionArgs implements Serializable {
    * @return the partitionArgs
    */
   public boolean hasPartitionAttributes() {
-    return this.partitionArgs.hasPartitionAttributes();
+    return this.partitionArgs != null && this.partitionArgs.hasPartitionAttributes();
   }
 
   /**
@@ -439,8 +468,8 @@ public class RegionFunctionArgs implements Serializable {
     return this.compressor;
   }
 
-  public EvictionAttributes getEvictionAttributes() {
-    return evictionAttributes != null ? evictionAttributes.convertToEvictionAttributes() : null;
+  public EvictionAttrs getEvictionAttributes() {
+    return this.evictionAttributes;
   }
 
   /**
@@ -601,6 +630,35 @@ public class RegionFunctionArgs implements Serializable {
         return EvictionAttributes.createLRUEntryAttributes(maxEntryCount, action);
       }
     }
+
+    public RegionAttributesType.EvictionAttributes convertToConfigEvictionAttributes() {
+      RegionAttributesType.EvictionAttributes configAttributes =
+          new RegionAttributesType.EvictionAttributes();
+      EnumActionDestroyOverflow action = EnumActionDestroyOverflow.fromValue(evictionAction);
+
+      if (maxMemory == null && maxEntryCount == null) {
+        RegionAttributesType.EvictionAttributes.LruHeapPercentage heapPercentage =
+            new RegionAttributesType.EvictionAttributes.LruHeapPercentage();
+        heapPercentage.setAction(action);
+        heapPercentage.setClassName(objectSizer);
+        configAttributes.setLruHeapPercentage(heapPercentage);
+      } else if (maxMemory != null) {
+        RegionAttributesType.EvictionAttributes.LruMemorySize memorySize =
+            new RegionAttributesType.EvictionAttributes.LruMemorySize();
+        memorySize.setAction(action);
+        memorySize.setClassName(objectSizer);
+        memorySize.setMaximum(maxMemory.toString());
+        configAttributes.setLruMemorySize(memorySize);
+      } else {
+        RegionAttributesType.EvictionAttributes.LruEntryCount entryCount =
+            new RegionAttributesType.EvictionAttributes.LruEntryCount();
+        entryCount.setAction(action);
+        entryCount.setMaximum(maxEntryCount.toString());
+        configAttributes.setLruEntryCount(entryCount);
+      }
+
+      return configAttributes;
+    }
   }
 
 
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/i18n/CliStrings.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/i18n/CliStrings.java
index a7cbd16..bd96248 100644
--- a/geode-core/src/main/java/org/apache/geode/management/internal/cli/i18n/CliStrings.java
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/i18n/CliStrings.java
@@ -946,6 +946,8 @@ public class CliStrings {
   public static final String CREATE_REGION__TOTALNUMBUCKETS__HELP =
       "Sets the total number of hash buckets to be used by the region in all processes. (Default: "
           + PartitionAttributesFactory.GLOBAL_MAX_BUCKETS_DEFAULT + ").";
+  public static final String CREATE_REGION__MSG__CANNOT_DISABLE_CLONING_WITH_COMPRESSOR =
+      "Cannot set enable-cloning to false when compressor is provided";
   public static final String CREATE_REGION__MSG__SPECIFY_VALID_REGION_PATH =
       "Specify a valid " + CliStrings.CREATE_REGION__REGION;
   public static final String CREATE_REGION__MSG__PARENT_REGION_FOR_0_DOES_NOT_EXIST =
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/util/RegionPath.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/util/RegionPath.java
index aac49bf..3bd548b 100644
--- a/geode-core/src/main/java/org/apache/geode/management/internal/cli/util/RegionPath.java
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/util/RegionPath.java
@@ -14,7 +14,9 @@
  */
 package org.apache.geode.management.internal.cli.util;
 
+import java.util.ArrayList;
 import java.util.LinkedList;
+import java.util.List;
 
 import org.apache.geode.cache.Cache;
 import org.apache.geode.cache.Region;
@@ -67,6 +69,20 @@ public class RegionPath {
     return regionParentPath;
   }
 
+  public String[] getRegionsOnParentPath() {
+    String[] regionsOnPath = getParent().split(Region.SEPARATOR);
+
+    // Ignore preceding separator if there is one
+    int start = regionsOnPath[0] == null || regionsOnPath[0].isEmpty() ? 1 : 0;
+
+    List<String> regions = new ArrayList<>();
+    for (int i = start; i < regionsOnPath.length; i++) {
+      regions.add(regionsOnPath[i]);
+    }
+
+    return regions.toArray(new String[] {});
+  }
+
   /**
    * @return Parent RegionPath of this RegionPath. null if this is a root region
    */
diff --git a/geode-core/src/main/java/org/apache/geode/redis/internal/RegionProvider.java b/geode-core/src/main/java/org/apache/geode/redis/internal/RegionProvider.java
index 8d38c49..d3649f1 100644
--- a/geode-core/src/main/java/org/apache/geode/redis/internal/RegionProvider.java
+++ b/geode-core/src/main/java/org/apache/geode/redis/internal/RegionProvider.java
@@ -41,9 +41,9 @@ import org.apache.geode.cache.query.QueryService;
 import org.apache.geode.cache.query.RegionNotFoundException;
 import org.apache.geode.internal.cache.GemFireCacheImpl;
 import org.apache.geode.internal.hll.HyperLogLogPlus;
-import org.apache.geode.management.cli.Result;
 import org.apache.geode.management.cli.Result.Status;
 import org.apache.geode.management.internal.cli.commands.CreateRegionCommand;
+import org.apache.geode.management.internal.cli.result.model.ResultModel;
 import org.apache.geode.redis.GeodeRedisServer;
 import org.apache.geode.redis.internal.executor.ExpirationExecutor;
 import org.apache.geode.redis.internal.executor.ListQuery;
@@ -399,17 +399,19 @@ public class RegionProvider implements Closeable {
       return r;
     do {
       createRegionCmd.setCache(cache);
-      Result result = createRegionCmd.createRegion(regionPath, defaultRegionType, null, null, true,
-          null, null, null, null, null, null, null, null, false, false, true, false, false, false,
-          true, null, null, null, null, null, null, null, null, null, null, null, null, null, false,
-          null, null, null, null, null, null, null, null, null, null, null);
+      ResultModel resultModel =
+          createRegionCmd.createRegion(regionPath, defaultRegionType, null, null, true,
+              null, null, null, null, null, null, null, null, false, false, true, false, false,
+              false,
+              true, null, null, null, null, null, null, null, null, null, null, null, null, null,
+              false,
+              null, null, null, null, null, null, null, null, null, null, null);
 
       r = cache.getRegion(regionPath);
-      if (result.getStatus() == Status.ERROR && r == null) {
+      if (resultModel.getStatus() == Status.ERROR && r == null) {
         String err = "Unable to create region named \"" + regionPath + "\":\n";
-        while (result.hasNextLine())
-          err += result.nextLine();
-        throw new RegionCreationException(err);
+        // TODO: check this
+        throw new RegionCreationException(err + resultModel.toJson());
       }
     } while (r == null); // The region can be null in the case that it is concurrently destroyed by
     // a remote even triggered internally by Geode
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 4d68704..83ea16b 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
@@ -172,31 +172,31 @@ public class CreateRegionCommandTest {
     assertThat(args.isIfNotExists()).isFalse();
     assertThat(args.getKeyConstraint()).isNull();
     assertThat(args.getValueConstraint()).isNull();
-    assertThat(args.isStatisticsEnabled()).isNull();
+    assertThat(args.getStatisticsEnabled()).isNull();
 
     ExpirationAttrs empty = new ExpirationAttrs(null, null);
-    assertThat(args.getEntryExpirationIdleTime()).isEqualTo(empty);
-    assertThat(args.getEntryExpirationTTL()).isEqualTo(empty);
-    assertThat(args.getRegionExpirationIdleTime()).isEqualTo(empty);
-    assertThat(args.getRegionExpirationTTL()).isEqualTo(empty);
+    assertThat(args.getEntryExpirationIdleTime()).isNull();
+    assertThat(args.getEntryExpirationTTL()).isNull();
+    assertThat(args.getRegionExpirationIdleTime()).isNull();
+    assertThat(args.getRegionExpirationTTL()).isNull();
 
     assertThat(args.getDiskStore()).isNull();
-    assertThat(args.isDiskSynchronous()).isNull();
-    assertThat(args.isEnableAsyncConflation()).isNull();
-    assertThat(args.isEnableSubscriptionConflation()).isNull();
+    assertThat(args.getDiskSynchronous()).isNull();
+    assertThat(args.getEnableAsyncConflation()).isNull();
+    assertThat(args.getEnableSubscriptionConflation()).isNull();
     assertThat(args.getCacheListeners()).isEmpty();
     assertThat(args.getCacheLoader()).isNull();
     assertThat(args.getCacheWriter()).isNull();
     assertThat(args.getAsyncEventQueueIds()).isEmpty();
     assertThat(args.getGatewaySenderIds()).isEmpty();
-    assertThat(args.isConcurrencyChecksEnabled()).isNull();
-    assertThat(args.isCloningEnabled()).isNull();
-    assertThat(args.isMcastEnabled()).isNull();
+    assertThat(args.getConcurrencyChecksEnabled()).isNull();
+    assertThat(args.getCloningEnabled()).isNull();
+    assertThat(args.getMcastEnabled()).isNull();
     assertThat(args.getConcurrencyLevel()).isNull();
-    assertThat(args.getPartitionArgs()).isNotNull();
+    assertThat(args.getPartitionArgs()).isNull();
     assertThat(args.getEvictionMax()).isNull();
     assertThat(args.getCompressor()).isNull();
-    assertThat(args.isOffHeap()).isNull();
+    assertThat(args.getOffHeap()).isNull();
     assertThat(args.getRegionAttributes()).isNull();
   }
 
diff --git a/geode-core/src/test/java/org/apache/geode/management/internal/cli/domain/RegionConfigFactoryTest.java b/geode-core/src/test/java/org/apache/geode/management/internal/cli/domain/RegionConfigFactoryTest.java
new file mode 100644
index 0000000..31b5bd9
--- /dev/null
+++ b/geode-core/src/test/java/org/apache/geode/management/internal/cli/domain/RegionConfigFactoryTest.java
@@ -0,0 +1,273 @@
+/*
+ * 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 java.util.List;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import org.apache.geode.cache.EvictionAction;
+import org.apache.geode.cache.ExpirationAction;
+import org.apache.geode.cache.configuration.ClassNameType;
+import org.apache.geode.cache.configuration.DeclarableType;
+import org.apache.geode.cache.configuration.EnumActionDestroyOverflow;
+import org.apache.geode.cache.configuration.RegionAttributesType;
+import org.apache.geode.cache.configuration.RegionConfig;
+import org.apache.geode.management.internal.cli.functions.RegionFunctionArgs;
+
+public class RegionConfigFactoryTest {
+
+  RegionConfigFactory subject;
+  RegionFunctionArgs args;
+
+  @Before
+  public void setup() {
+    subject = new RegionConfigFactory();
+    args = new RegionFunctionArgs();
+    args.setRegionPath("region-name");
+  }
+
+  @Test
+  public void generatesConfigForRegion() {
+    RegionConfig config = subject.generate(args);
+    assertThat(config.getName()).isEqualTo("region-name");
+  }
+
+  @Test
+  public void generatesConfigForSubRegion() {
+    args.setRegionPath("region-name/subregion");
+
+    RegionConfig config = subject.generate(args);
+    assertThat(config.getName()).isEqualTo("subregion");
+  }
+
+  @Test
+  public void generatesWithNoAttributes() {
+    RegionConfig config = subject.generate(args);
+    assertThat(config.getRegionAttributes()).isEmpty();
+  }
+
+  @Test
+  public void generatesWithConstraintAttributes() {
+    args.setKeyConstraint("key-const");
+    args.setValueConstraint("value-const");
+
+    RegionConfig config = subject.generate(args);
+    assertThat(getRegionAttributeValue(config, t -> t.getKeyConstraint())).isEqualTo("key-const");
+    assertThat(getRegionAttributeValue(config, t -> t.getValueConstraint()))
+        .isEqualTo("value-const");
+  }
+
+  @Test
+  public void generatesWithExpirationIdleTimeAttributes() {
+    args.setRegionExpirationTTL(10, ExpirationAction.DESTROY);
+    args.setRegionExpirationIdleTime(3, ExpirationAction.INVALIDATE);
+    args.setEntryExpirationTTL(1, ExpirationAction.LOCAL_DESTROY);
+    args.setEntryExpirationIdleTime(12, ExpirationAction.LOCAL_DESTROY);
+    args.setEntryIdleTimeCustomExpiry(new ClassName<>("java.lang.String"));
+
+    RegionConfig config = subject.generate(args);
+    RegionAttributesType.RegionTimeToLive regionTimeToLive =
+        (RegionAttributesType.RegionTimeToLive) getRegionAttributeValue(config,
+            t -> t.getRegionTimeToLive());
+    assertThat(regionTimeToLive.getExpirationAttributes().getTimeout()).isEqualTo("10");
+
+    RegionAttributesType.EntryTimeToLive entryTimeToLive =
+        (RegionAttributesType.EntryTimeToLive) getRegionAttributeValue(config,
+            t -> t.getEntryTimeToLive());
+    assertThat(entryTimeToLive.getExpirationAttributes().getAction())
+        .isEqualTo(ExpirationAction.LOCAL_DESTROY.toXmlString());
+
+    RegionAttributesType.EntryIdleTime entryIdleTime =
+        (RegionAttributesType.EntryIdleTime) getRegionAttributeValue(config,
+            t -> t.getEntryIdleTime());
+    DeclarableType customExpiry = entryIdleTime.getExpirationAttributes().getCustomExpiry();
+    assertThat(customExpiry.getClassName()).isEqualTo("java.lang.String");
+    assertThat(entryIdleTime.getExpirationAttributes().getAction())
+        .isEqualTo(ExpirationAction.LOCAL_DESTROY.toXmlString());
+    assertThat(entryIdleTime.getExpirationAttributes().getTimeout())
+        .isEqualTo("12");
+  }
+
+  @Test
+  public void generatesWithDiskAttributes() {
+    args.setDiskStore("disk-store");
+    args.setDiskSynchronous(false);
+
+    RegionConfig config = subject.generate(args);
+    assertThat(getRegionAttributeValue(config, t -> t.getDiskStoreName())).isEqualTo("disk-store");
+    assertThat(getRegionAttributeValue(config, t -> t.isDiskSynchronous())).isEqualTo(false);
+  }
+
+  @Test
+  public void generatesWithPrAttributes() {
+    args.setPartitionArgs("colo-with", 100,
+        100L, 100, 100L,
+        100L, 100, "java.lang.String");
+
+    RegionConfig config = subject.generate(args);
+    RegionAttributesType.PartitionAttributes partitionAttributes =
+        (RegionAttributesType.PartitionAttributes) getRegionAttributeValue(config,
+            t -> t.getPartitionAttributes());
+    assertThat(partitionAttributes).isNotNull();
+    assertThat(partitionAttributes.getColocatedWith()).isEqualTo("colo-with");
+    assertThat(partitionAttributes.getLocalMaxMemory()).isEqualTo("100");
+    assertThat(partitionAttributes.getRecoveryDelay()).isEqualTo("100");
+    assertThat(partitionAttributes.getRedundantCopies()).isEqualTo("100");
+    assertThat(partitionAttributes.getStartupRecoveryDelay()).isEqualTo("100");
+    assertThat(partitionAttributes.getTotalMaxMemory()).isEqualTo("100");
+    assertThat(partitionAttributes.getTotalNumBuckets()).isEqualTo("100");
+
+    DeclarableType partitionResolverType = partitionAttributes.getPartitionResolver();
+    assertThat(partitionResolverType.getClassName()).isEqualTo("java.lang.String");
+  }
+
+  @Test
+  public void generatesWithMiscBooleanFlags() {
+    args.setStatisticsEnabled(false);
+    args.setEnableAsyncConflation(false);
+    args.setConcurrencyChecksEnabled(true);
+    args.setEnableSubscriptionConflation(true);
+    args.setMcastEnabled(false);
+    args.setCloningEnabled(false);
+    args.setOffHeap(true);
+    RegionConfig config = subject.generate(args);
+
+    assertThat(getRegionAttributeValue(config, t -> t.isStatisticsEnabled())).isEqualTo(false);
+    assertThat(getRegionAttributeValue(config, t -> t.isEnableSubscriptionConflation()))
+        .isEqualTo(true);
+    assertThat(getRegionAttributeValue(config, t -> t.isConcurrencyChecksEnabled()))
+        .isEqualTo(true);
+    assertThat(getRegionAttributeValue(config, t -> t.isEnableSubscriptionConflation()))
+        .isEqualTo(true);
+    assertThat(getRegionAttributeValue(config, t -> t.isMulticastEnabled()))
+        .isEqualTo(false);
+    assertThat(getRegionAttributeValue(config, t -> t.isCloningEnabled())).isEqualTo(false);
+    assertThat(getRegionAttributeValue(config, t -> t.isOffHeap())).isEqualTo(true);
+  }
+
+  @Test
+  public void generatesWithGatewayFlags() {
+    args.setGatewaySenderIds(new String[] {"some-id", "some-other-id"});
+    RegionConfig config = subject.generate(args);
+
+    assertThat((String) getRegionAttributeValue(config, t -> t.getGatewaySenderIds()))
+        .contains("some-id");
+    assertThat((String) getRegionAttributeValue(config, t -> t.getGatewaySenderIds()))
+        .contains("some-other-id");
+  }
+
+  @Test
+  public void generatesWithEvictionHeapPercentageFlags() {
+    args.setEvictionAttributes(EvictionAction.LOCAL_DESTROY.toString(), null, null,
+        "java.lang.String");
+    RegionConfig config = subject.generate(args);
+
+    RegionAttributesType.EvictionAttributes evictionAttributes =
+        (RegionAttributesType.EvictionAttributes) getRegionAttributeValue(config,
+            t -> t.getEvictionAttributes());
+    assertThat(evictionAttributes).isNotNull();
+    assertThat(evictionAttributes.getLruHeapPercentage().getAction())
+        .isSameAs(EnumActionDestroyOverflow.LOCAL_DESTROY);
+    assertThat(evictionAttributes.getLruHeapPercentage().getClassName())
+        .isEqualTo("java.lang.String");
+  }
+
+  @Test
+  public void generatesWithEvictionMaxMemory() {
+    args.setEvictionAttributes(EvictionAction.LOCAL_DESTROY.toString(), 100, null,
+        null);
+    RegionConfig config = subject.generate(args);
+
+    RegionAttributesType.EvictionAttributes evictionAttributes =
+        (RegionAttributesType.EvictionAttributes) getRegionAttributeValue(config,
+            t -> t.getEvictionAttributes());
+    assertThat(evictionAttributes).isNotNull();
+    assertThat(evictionAttributes.getLruMemorySize().getAction())
+        .isSameAs(EnumActionDestroyOverflow.LOCAL_DESTROY);
+    assertThat(evictionAttributes.getLruMemorySize().getMaximum()).isEqualTo("100");
+  }
+
+  @Test
+  public void generatesWithEvictionMaxEntry() {
+    args.setEvictionAttributes(EvictionAction.OVERFLOW_TO_DISK.toString(), null, 1,
+        null);
+    RegionConfig config = subject.generate(args);
+    RegionAttributesType.EvictionAttributes evictionAttributes =
+        (RegionAttributesType.EvictionAttributes) getRegionAttributeValue(config,
+            t -> t.getEvictionAttributes());
+    assertThat(evictionAttributes).isNotNull();
+    assertThat(evictionAttributes.getLruEntryCount().getAction())
+        .isSameAs(EnumActionDestroyOverflow.OVERFLOW_TO_DISK);
+    assertThat(evictionAttributes.getLruEntryCount().getMaximum()).isEqualTo("1");
+  }
+
+  @Test
+  public void generatesWithAsyncEventQueueIds() {
+    args.setAsyncEventQueueIds(new String[] {"id-1", "id-2"});
+    RegionConfig config = subject.generate(args);
+
+    assertThat((String) getRegionAttributeValue(config, t -> t.getAsyncEventQueueIds()))
+        .contains("id-1");
+    assertThat((String) getRegionAttributeValue(config, t -> t.getAsyncEventQueueIds()))
+        .contains("id-2");
+  }
+
+  @Test
+  public void generatesWithCacheClasses() {
+    args.setCacheListeners(new ClassName[] {new ClassName("java.lang.String")});
+    args.setCacheLoader(new ClassName("java.lang.String"));
+    args.setCacheWriter(new ClassName("java.lang.String"));
+    RegionConfig config = subject.generate(args);
+
+    List<DeclarableType> cacheListeners = config.getRegionAttributes().stream()
+        .filter(a -> !a.getCacheListeners().isEmpty())
+        .findFirst()
+        .map(a -> a.getCacheListeners())
+        .orElse(null);
+
+    assertThat(cacheListeners).isNotNull();
+    assertThat(cacheListeners.get(0).getClassName()).isEqualTo("java.lang.String");
+    assertThat(
+        ((DeclarableType) getRegionAttributeValue(config, t -> t.getCacheLoader())).getClassName())
+            .isEqualTo("java.lang.String");
+    assertThat(
+        ((DeclarableType) getRegionAttributeValue(config, t -> t.getCacheWriter())).getClassName())
+            .isEqualTo("java.lang.String");
+  }
+
+  @Test
+  public void generatesWithOtherMiscSimpleFlags() {
+    args.setCompressor("java.lang.String");
+    args.setConcurrencyLevel(1);
+
+    RegionConfig config = subject.generate(args);
+
+    assertThat(
+        ((ClassNameType) getRegionAttributeValue(config, t -> t.getCompressor())).getClassName())
+            .isEqualTo("java.lang.String");
+    assertThat(getRegionAttributeValue(config, t -> t.getConcurrencyLevel())).isEqualTo("1");
+  }
+
+  private Object getRegionAttributeValue(RegionConfig config, RegionAttributeGetFunction function) {
+    return config.getRegionAttributes().stream()
+        .findFirst()
+        .map(a -> function.getValue(a))
+        .orElse(null);
+  }
+}
diff --git a/geode-core/src/test/java/org/apache/geode/management/internal/cli/functions/RegionFunctionArgsTest.java b/geode-core/src/test/java/org/apache/geode/management/internal/cli/functions/RegionFunctionArgsTest.java
index de22efb..12d6dd5 100644
--- a/geode-core/src/test/java/org/apache/geode/management/internal/cli/functions/RegionFunctionArgsTest.java
+++ b/geode-core/src/test/java/org/apache/geode/management/internal/cli/functions/RegionFunctionArgsTest.java
@@ -37,16 +37,40 @@ public class RegionFunctionArgsTest {
 
   @Test
   public void defaultRegionFunctionArgs() throws Exception {
-    assertThat(args.isDiskSynchronous()).isNull();
-    assertThat(args.isCloningEnabled()).isNull();
-    assertThat(args.isConcurrencyChecksEnabled()).isNull();
+    assertThat(args.getDiskSynchronous()).isNull();
+    assertThat(args.getCloningEnabled()).isNull();
+    assertThat(args.getConcurrencyChecksEnabled()).isNull();
     assertThat(args.getConcurrencyLevel()).isNull();
-    assertThat(args.getPartitionArgs()).isNotNull();
-    assertThat(args.getPartitionArgs().hasPartitionAttributes()).isFalse();
+    assertThat(args.getPartitionArgs()).isNull();
+    assertThat(args.hasPartitionAttributes()).isFalse();
     assertThat(args.getEvictionAttributes()).isNull();
   }
 
   @Test
+  public void emptyPartitionArgsShouldBeNull() throws Exception {
+    args.setPartitionArgs(null, null, null,
+        null, null, null,
+        null, null);
+    assertThat(args.getPartitionArgs()).isNull();
+    assertThat(args.hasPartitionAttributes()).isFalse();
+  }
+
+  @Test
+  public void emptyExpirationAttributesShouldBeNull() throws Exception {
+    args.setEntryExpirationIdleTime(null, null);
+    assertThat(args.getEntryExpirationIdleTime()).isNull();
+
+    args.setEntryExpirationTTL(null, null);
+    assertThat(args.getEntryExpirationTTL()).isNull();
+
+    args.setRegionExpirationIdleTime(null, null);
+    assertThat(args.getRegionExpirationIdleTime()).isNull();
+
+    args.setRegionExpirationTTL(null, null);
+    assertThat(args.getRegionExpirationTTL()).isNull();
+  }
+
+  @Test
   public void defaultPartitionArgs() throws Exception {
     assertThat(partitionArgs.hasPartitionAttributes()).isFalse();
 
@@ -64,19 +88,22 @@ public class RegionFunctionArgsTest {
     assertThat(args.getEvictionAttributes()).isNull();
 
     args.setEvictionAttributes("local-destroy", null, null, null);
-    EvictionAttributes attributes = args.getEvictionAttributes();
+    EvictionAttributes attributes = args.getEvictionAttributes()
+        .convertToEvictionAttributes();
     assertThat(attributes.getAlgorithm()).isEqualTo(EvictionAlgorithm.LRU_HEAP);
     assertThat(attributes.getAction()).isEqualTo(EvictionAction.LOCAL_DESTROY);
     assertThat(attributes.getMaximum()).isEqualTo(0);
 
     args.setEvictionAttributes("overflow-to-disk", 1000, null, null);
-    EvictionAttributes attributes1 = args.getEvictionAttributes();
+    EvictionAttributes attributes1 = args.getEvictionAttributes()
+        .convertToEvictionAttributes();
     assertThat(attributes1.getAlgorithm()).isEqualTo(EvictionAlgorithm.LRU_MEMORY);
     assertThat(attributes1.getAction()).isEqualTo(EvictionAction.OVERFLOW_TO_DISK);
     assertThat(attributes1.getMaximum()).isEqualTo(1000);
 
     args.setEvictionAttributes("local-destroy", null, 1000, null);
-    EvictionAttributes attributes2 = args.getEvictionAttributes();
+    EvictionAttributes attributes2 = args.getEvictionAttributes()
+        .convertToEvictionAttributes();
     assertThat(attributes2.getAlgorithm()).isEqualTo(EvictionAlgorithm.LRU_ENTRY);
     assertThat(attributes2.getAction()).isEqualTo(EvictionAction.LOCAL_DESTROY);
     assertThat(attributes2.getMaximum()).isEqualTo(1000);
@@ -85,7 +112,7 @@ public class RegionFunctionArgsTest {
   @Test
   public void evictionAttributesWithNullAction() throws Exception {
     args.setEvictionAttributes(null, null, 1000, null);
-    EvictionAttributes attributes3 = args.getEvictionAttributes();
+    RegionFunctionArgs.EvictionAttrs attributes3 = args.getEvictionAttributes();
     assertThat(attributes3).isNull();
   }
 }
diff --git a/geode-wan/src/distributedTest/java/org/apache/geode/management/internal/cli/commands/CreateRegionCommandDUnitTest.java b/geode-wan/src/distributedTest/java/org/apache/geode/management/internal/cli/commands/CreateRegionCommandDUnitTest.java
index 365eb73..57d91a3 100644
--- a/geode-wan/src/distributedTest/java/org/apache/geode/management/internal/cli/commands/CreateRegionCommandDUnitTest.java
+++ b/geode-wan/src/distributedTest/java/org/apache/geode/management/internal/cli/commands/CreateRegionCommandDUnitTest.java
@@ -14,13 +14,17 @@
  */
 package org.apache.geode.management.internal.cli.commands;
 
+import static org.assertj.core.api.Assertions.assertThat;
+
 import org.junit.BeforeClass;
 import org.junit.ClassRule;
+import org.junit.Ignore;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.experimental.categories.Category;
 import org.junit.rules.TestName;
 
+import org.apache.geode.cache.Region;
 import org.apache.geode.test.dunit.IgnoredException;
 import org.apache.geode.test.dunit.rules.ClusterStartupRule;
 import org.apache.geode.test.dunit.rules.MemberVM;
@@ -65,9 +69,9 @@ public class CreateRegionCommandDUnitTest {
         + " --async-event-queue-id=" + asyncQueueName)
         .statusIsError()
         .containsOutput("server-1",
-            "ERROR: Parallel Async Event Queue " + asyncQueueName
+            "Parallel Async Event Queue " + asyncQueueName
                 + " can not be used with replicated region /" + regionName)
-        .containsOutput("server-2", "ERROR: Parallel Async Event Queue " + asyncQueueName
+        .containsOutput("server-2", "Parallel Async Event Queue " + asyncQueueName
             + " can not be used with replicated region /" + regionName);
 
     // The exception must be thrown early in the initialization, so the region itself shouldn't be
@@ -91,13 +95,56 @@ public class CreateRegionCommandDUnitTest {
         + " --gateway-sender-id=" + gatewaySenderName)
         .statusIsError()
         .containsOutput("server-1",
-            "ERROR: Parallel gateway sender " + gatewaySenderName
+            "Parallel gateway sender " + gatewaySenderName
                 + " can not be used with replicated region /" + regionName)
-        .containsOutput("server-2", "ERROR: Parallel gateway sender " + gatewaySenderName
+        .containsOutput("server-2", "Parallel gateway sender " + gatewaySenderName
             + " can not be used with replicated region /" + regionName);
 
     // The exception must be thrown early in the initialization, so the region itself shouldn't be
     // added to the root regions.
     gfsh.executeAndAssertThat("list regions").statusIsSuccess().doesNotContainOutput(regionName);
   }
+
+  /**
+   * Ignored this test until we refactor the FetchRegionAttributesFunction to not use
+   * AttributesFactory, and instead use RegionConfig, which we will do as part of implementing
+   * GEODE-6103
+   */
+  @Ignore
+  @Test
+  public void createRegionFromTemplateWithGatewaySender() throws Exception {
+    String regionName = testName.getMethodName();
+    String sender = "sender1";
+    String remoteDS = "2";
+    IgnoredException.addIgnoredException("could not get remote locator information");
+
+    gfsh.executeAndAssertThat("create gateway-sender"
+        + " --id=" + sender
+        + " --remote-distributed-system-id=" + remoteDS).statusIsSuccess();
+
+    // Give gateway sender time to get created
+    Thread.sleep(2000);
+
+    gfsh.executeAndAssertThat("create region"
+        + " --name=" + regionName
+        + " --type=REPLICATE_PERSISTENT"
+        + " --gateway-sender-id=" + sender).statusIsSuccess();
+
+    String regionNameFromTemplate = regionName + "-from-template";
+    gfsh.executeAndAssertThat("create region --name=" + regionNameFromTemplate
+        + " --template-region=" + regionName)
+        .statusIsSuccess();
+
+    server1.invoke(() -> {
+      Region region1 = ClusterStartupRule.getCache().getRegion(regionNameFromTemplate);
+      assertThat(region1.getAttributes().getGatewaySenderIds())
+          .describedAs("region1 contains gateway sender")
+          .contains(sender);
+
+      Region region2 = ClusterStartupRule.getCache().getRegion(regionNameFromTemplate);
+      assertThat(region2.getAttributes().getGatewaySenderIds())
+          .describedAs("region2 contains gateway sender")
+          .contains(sender);
+    });
+  }
 }


[geode] 02/03: GEODE-5971: RegionConfig can only have one RegionAttributesType

Posted by ji...@apache.org.
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

commit 846af4e2df0b6c76585e8a16e1eeb26e71e9c2dd
Author: Jinmei Liao <ji...@pivotal.io>
AuthorDate: Mon Dec 3 22:51:49 2018 -0800

    GEODE-5971: RegionConfig can only have one RegionAttributesType
    
    Signed-off-by: Jinmei Liao <ji...@pivotal.io>
---
 .../cli/CreateMappingCommandDUnitTest.java         |   2 +-
 .../cli/DestroyMappingCommandDunitTest.java        |   2 +-
 .../jdbc/internal/cli/CreateMappingCommand.java    |  28 +++---
 .../jdbc/internal/cli/DestroyMappingCommand.java   |  22 ++---
 .../internal/cli/CreateMappingCommandTest.java     |  24 ++---
 .../internal/cli/DestroyMappingCommandTest.java    |   4 +-
 ...egionCommandPersistsConfigurationDUnitTest.java | 110 +++++++++++++--------
 .../commands/DestroyRegionCommandDUnitTest.java    |   7 +-
 .../main/java/org/apache/geode/cache/Scope.java    |   4 +
 .../geode/cache/configuration/RegionConfig.java    |  45 ++-------
 .../cli/domain/RegionAttributeGetFunction.java     |  22 -----
 .../cli/domain/RegionAttributeSetFunction.java     |  22 -----
 .../internal/cli/domain/RegionConfigFactory.java   |  36 ++++---
 .../cli/functions/RegionCreateFunction.java        |  14 ---
 .../sanctioned-geode-core-serializables.txt        |   2 +-
 .../geode/cache/configuration/CacheConfigTest.java |  18 ++++
 .../cli/domain/RegionConfigFactoryTest.java        |  76 ++++++--------
 17 files changed, 187 insertions(+), 251 deletions(-)

diff --git a/geode-connectors/src/distributedTest/java/org/apache/geode/connectors/jdbc/internal/cli/CreateMappingCommandDUnitTest.java b/geode-connectors/src/distributedTest/java/org/apache/geode/connectors/jdbc/internal/cli/CreateMappingCommandDUnitTest.java
index d71f257..2bd74ef 100644
--- a/geode-connectors/src/distributedTest/java/org/apache/geode/connectors/jdbc/internal/cli/CreateMappingCommandDUnitTest.java
+++ b/geode-connectors/src/distributedTest/java/org/apache/geode/connectors/jdbc/internal/cli/CreateMappingCommandDUnitTest.java
@@ -142,7 +142,7 @@ public class CreateMappingCommandDUnitTest {
     RegionConfig regionConfig = cacheConfig.getRegions().stream()
         .filter(region -> region.getName().equals(convertRegionPathToName(regionName))).findFirst()
         .orElse(null);
-    RegionAttributesType attributes = regionConfig.getRegionAttributes().get(0);
+    RegionAttributesType attributes = regionConfig.getRegionAttributes();
     assertThat(attributes.getCacheLoader().getClassName()).isEqualTo(JdbcLoader.class.getName());
     if (synchronous) {
       assertThat(attributes.getCacheWriter().getClassName()).isEqualTo(JdbcWriter.class.getName());
diff --git a/geode-connectors/src/distributedTest/java/org/apache/geode/connectors/jdbc/internal/cli/DestroyMappingCommandDunitTest.java b/geode-connectors/src/distributedTest/java/org/apache/geode/connectors/jdbc/internal/cli/DestroyMappingCommandDunitTest.java
index a7b8d38..2cfcc7e 100644
--- a/geode-connectors/src/distributedTest/java/org/apache/geode/connectors/jdbc/internal/cli/DestroyMappingCommandDunitTest.java
+++ b/geode-connectors/src/distributedTest/java/org/apache/geode/connectors/jdbc/internal/cli/DestroyMappingCommandDunitTest.java
@@ -203,7 +203,7 @@ public class DestroyMappingCommandDunitTest implements Serializable {
         InternalLocator.getLocator().getConfigurationPersistenceService().getCacheConfig(null);
     RegionConfig regionConfig = cacheConfig.getRegions().stream()
         .filter(region -> region.getName().equals(REGION_NAME)).findFirst().orElse(null);
-    RegionAttributesType attributes = regionConfig.getRegionAttributes().get(0);
+    RegionAttributesType attributes = regionConfig.getRegionAttributes();
     assertThat(attributes.getCacheLoader()).isNull();
     if (synchronous) {
       assertThat(attributes.getCacheWriter()).isNull();
diff --git a/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/CreateMappingCommand.java b/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/CreateMappingCommand.java
index dd47895..5515f42 100644
--- a/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/CreateMappingCommand.java
+++ b/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/CreateMappingCommand.java
@@ -147,8 +147,7 @@ public class CreateMappingCommand extends SingleGfshCommand {
 
   private void checkForCacheLoader(String regionName, RegionConfig regionConfig)
       throws PreconditionException {
-    RegionAttributesType regionAttributes = regionConfig.getRegionAttributes().stream()
-        .filter(attributes -> attributes.getCacheLoader() != null).findFirst().orElse(null);
+    RegionAttributesType regionAttributes = regionConfig.getRegionAttributes();
     if (regionAttributes != null) {
       DeclarableType loaderDeclarable = regionAttributes.getCacheLoader();
       if (loaderDeclarable != null) {
@@ -162,8 +161,7 @@ public class CreateMappingCommand extends SingleGfshCommand {
   private void checkForCacheWriter(String regionName, boolean synchronous,
       RegionConfig regionConfig) throws PreconditionException {
     if (synchronous) {
-      RegionAttributesType writerAttributes = regionConfig.getRegionAttributes().stream()
-          .filter(attributes -> attributes.getCacheWriter() != null).findFirst().orElse(null);
+      RegionAttributesType writerAttributes = regionConfig.getRegionAttributes();
       if (writerAttributes != null) {
         DeclarableType writerDeclarable = writerAttributes.getCacheWriter();
         if (writerDeclarable != null) {
@@ -200,7 +198,7 @@ public class CreateMappingCommand extends SingleGfshCommand {
       return false;
     }
 
-    RegionAttributesType attributes = getRegionAttributes(regionConfig);
+    RegionAttributesType attributes = getRegionAttribute(regionConfig);
     addMappingToRegion(regionMapping, regionConfig);
     if (!synchronous) {
       createAsyncQueue(cacheConfig, attributes, queueName);
@@ -210,6 +208,14 @@ public class CreateMappingCommand extends SingleGfshCommand {
     return true;
   }
 
+  private RegionAttributesType getRegionAttribute(RegionConfig config) {
+    if (config.getRegionAttributes() == null) {
+      config.setRegionAttributes(new RegionAttributesType());
+    }
+
+    return config.getRegionAttributes();
+  }
+
   @CliAvailabilityIndicator({CREATE_MAPPING})
   public boolean commandAvailable() {
     return isOnlineCommandAvailable();
@@ -272,16 +278,4 @@ public class CreateMappingCommand extends SingleGfshCommand {
     writer.setClassName(JdbcWriter.class.getName());
     attributes.setCacheWriter(writer);
   }
-
-  private RegionAttributesType getRegionAttributes(RegionConfig regionConfig) {
-    RegionAttributesType attributes;
-    List<RegionAttributesType> attributesList = regionConfig.getRegionAttributes();
-    if (attributesList.isEmpty()) {
-      attributes = new RegionAttributesType();
-      attributesList.add(attributes);
-    } else {
-      attributes = attributesList.get(0);
-    }
-    return attributes;
-  }
 }
diff --git a/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/DestroyMappingCommand.java b/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/DestroyMappingCommand.java
index 0f32a8f..36098bf 100644
--- a/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/DestroyMappingCommand.java
+++ b/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/DestroyMappingCommand.java
@@ -84,13 +84,21 @@ public class DestroyMappingCommand extends SingleGfshCommand {
     boolean modified = false;
     modified |= removeJdbcMappingFromRegion(regionConfig);
     modified |= removeJdbcQueueFromCache(cacheConfig, regionName);
-    RegionAttributesType attributes = getRegionAttributes(regionConfig);
+    RegionAttributesType attributes = getRegionAttribute(regionConfig);
     modified |= removeJdbcLoader(attributes);
     modified |= removeJdbcWriter(attributes);
     modified |= removeJdbcAsyncEventQueueId(attributes, regionName);
     return modified;
   }
 
+  private RegionAttributesType getRegionAttribute(RegionConfig config) {
+    if (config.getRegionAttributes() == null) {
+      config.setRegionAttributes(new RegionAttributesType());
+    }
+
+    return config.getRegionAttributes();
+  }
+
   private boolean removeJdbcLoader(RegionAttributesType attributes) {
     DeclarableType cacheLoader = attributes.getCacheLoader();
     if (cacheLoader != null) {
@@ -159,18 +167,6 @@ public class DestroyMappingCommand extends SingleGfshCommand {
         .filter(region -> region.getName().equals(regionName)).findFirst().orElse(null);
   }
 
-  private RegionAttributesType getRegionAttributes(RegionConfig regionConfig) {
-    RegionAttributesType attributes;
-    List<RegionAttributesType> attributesList = regionConfig.getRegionAttributes();
-    if (attributesList.isEmpty()) {
-      attributes = new RegionAttributesType();
-      attributesList.add(attributes);
-    } else {
-      attributes = attributesList.get(0);
-    }
-    return attributes;
-  }
-
   @CliAvailabilityIndicator({DESTROY_MAPPING})
   public boolean commandAvailable() {
     return isOnlineCommandAvailable();
diff --git a/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/CreateMappingCommandTest.java b/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/CreateMappingCommandTest.java
index cded45f..02211fa 100644
--- a/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/CreateMappingCommandTest.java
+++ b/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/CreateMappingCommandTest.java
@@ -97,11 +97,9 @@ public class CreateMappingCommandTest {
 
     matchingRegion = mock(RegionConfig.class);
     when(matchingRegion.getName()).thenReturn(regionName);
-    List<RegionAttributesType> attributesList = new ArrayList<>();
     matchingRegionAttributes = mock(RegionAttributesType.class);
     when(matchingRegionAttributes.getDataPolicy()).thenReturn(RegionAttributesDataPolicy.REPLICATE);
-    attributesList.add(matchingRegionAttributes);
-    when(matchingRegion.getRegionAttributes()).thenReturn(attributesList);
+    when(matchingRegion.getRegionAttributes()).thenReturn(matchingRegionAttributes);
 
     arguments[0] = mapping;
     arguments[1] = false;
@@ -205,13 +203,11 @@ public class CreateMappingCommandTest {
     List<RegionConfig> list = new ArrayList<>();
     list.add(matchingRegion);
     when(cacheConfig.getRegions()).thenReturn(list);
-    List<RegionAttributesType> attributes = new ArrayList<>();
     RegionAttributesType loaderAttribute = mock(RegionAttributesType.class);
     DeclarableType loaderDeclarable = mock(DeclarableType.class);
     when(loaderDeclarable.getClassName()).thenReturn(null);
     when(loaderAttribute.getCacheLoader()).thenReturn(loaderDeclarable);
-    attributes.add(loaderAttribute);
-    when(matchingRegion.getRegionAttributes()).thenReturn(attributes);
+    when(matchingRegion.getRegionAttributes()).thenReturn(loaderAttribute);
     List<CacheElement> customList = new ArrayList<>();
     RegionMapping existingMapping = mock(RegionMapping.class);
     customList.add(existingMapping);
@@ -235,13 +231,11 @@ public class CreateMappingCommandTest {
     List<RegionConfig> list = new ArrayList<>();
     list.add(matchingRegion);
     when(cacheConfig.getRegions()).thenReturn(list);
-    List<RegionAttributesType> attributes = new ArrayList<>();
     RegionAttributesType loaderAttribute = mock(RegionAttributesType.class);
     DeclarableType loaderDeclarable = mock(DeclarableType.class);
     when(loaderDeclarable.getClassName()).thenReturn("MyCacheLoaderClass");
     when(loaderAttribute.getCacheLoader()).thenReturn(loaderDeclarable);
-    attributes.add(loaderAttribute);
-    when(matchingRegion.getRegionAttributes()).thenReturn(attributes);
+    when(matchingRegion.getRegionAttributes()).thenReturn(loaderAttribute);
 
     ResultModel result = createRegionMappingCommand.createMapping(regionName, dataSourceName,
         tableName, pdxClass, false);
@@ -262,13 +256,11 @@ public class CreateMappingCommandTest {
     List<RegionConfig> list = new ArrayList<>();
     list.add(matchingRegion);
     when(cacheConfig.getRegions()).thenReturn(list);
-    List<RegionAttributesType> attributes = new ArrayList<>();
     RegionAttributesType writerAttribute = mock(RegionAttributesType.class);
     DeclarableType writerDeclarable = mock(DeclarableType.class);
     when(writerDeclarable.getClassName()).thenReturn("MyCacheWriterClass");
     when(writerAttribute.getCacheWriter()).thenReturn(writerDeclarable);
-    attributes.add(writerAttribute);
-    when(matchingRegion.getRegionAttributes()).thenReturn(attributes);
+    when(matchingRegion.getRegionAttributes()).thenReturn(writerAttribute);
 
     ResultModel result = createRegionMappingCommand.createMapping(regionName, dataSourceName,
         tableName, pdxClass, true);
@@ -289,11 +281,9 @@ public class CreateMappingCommandTest {
     List<RegionConfig> list = new ArrayList<>();
     list.add(matchingRegion);
     when(cacheConfig.getRegions()).thenReturn(list);
-    List<RegionAttributesType> attributes = new ArrayList<>();
     RegionAttributesType loaderAttribute = mock(RegionAttributesType.class);
     when(loaderAttribute.getCacheLoader()).thenReturn(null);
-    attributes.add(loaderAttribute);
-    when(matchingRegion.getRegionAttributes()).thenReturn(attributes);
+    when(matchingRegion.getRegionAttributes()).thenReturn(loaderAttribute);
     List<AsyncEventQueue> asyncEventQueues = new ArrayList<>();
     AsyncEventQueue matchingQueue = mock(AsyncEventQueue.class);
     String queueName = createRegionMappingCommand.createAsyncEventQueueName(regionName);
@@ -319,11 +309,9 @@ public class CreateMappingCommandTest {
     List<RegionConfig> list = new ArrayList<>();
     list.add(matchingRegion);
     when(cacheConfig.getRegions()).thenReturn(list);
-    List<RegionAttributesType> attributes = new ArrayList<>();
     RegionAttributesType loaderAttribute = mock(RegionAttributesType.class);
     when(loaderAttribute.getCacheLoader()).thenReturn(null);
-    attributes.add(loaderAttribute);
-    when(matchingRegion.getRegionAttributes()).thenReturn(attributes);
+    when(matchingRegion.getRegionAttributes()).thenReturn(loaderAttribute);
     List<AsyncEventQueue> asyncEventQueues = new ArrayList<>();
     AsyncEventQueue matchingQueue = mock(AsyncEventQueue.class);
     String queueName = createRegionMappingCommand.createAsyncEventQueueName(regionName);
diff --git a/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/DestroyMappingCommandTest.java b/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/DestroyMappingCommandTest.java
index 9018055..a633ff0 100644
--- a/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/DestroyMappingCommandTest.java
+++ b/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/DestroyMappingCommandTest.java
@@ -86,11 +86,9 @@ public class DestroyMappingCommandTest {
 
     matchingRegion = mock(RegionConfig.class);
     when(matchingRegion.getName()).thenReturn(regionName);
-    List<RegionAttributesType> attributesList = new ArrayList<>();
     matchingRegionAttributes = mock(RegionAttributesType.class);
     when(matchingRegionAttributes.getDataPolicy()).thenReturn(RegionAttributesDataPolicy.REPLICATE);
-    attributesList.add(matchingRegionAttributes);
-    when(matchingRegion.getRegionAttributes()).thenReturn(attributesList);
+    when(matchingRegion.getRegionAttributes()).thenReturn(matchingRegionAttributes);
   }
 
   @Test
diff --git a/geode-core/src/distributedTest/java/org/apache/geode/management/internal/cli/commands/CreateRegionCommandPersistsConfigurationDUnitTest.java b/geode-core/src/distributedTest/java/org/apache/geode/management/internal/cli/commands/CreateRegionCommandPersistsConfigurationDUnitTest.java
index 275fac9..c4e14f0 100644
--- a/geode-core/src/distributedTest/java/org/apache/geode/management/internal/cli/commands/CreateRegionCommandPersistsConfigurationDUnitTest.java
+++ b/geode-core/src/distributedTest/java/org/apache/geode/management/internal/cli/commands/CreateRegionCommandPersistsConfigurationDUnitTest.java
@@ -38,6 +38,7 @@ import org.apache.geode.cache.configuration.CacheConfig;
 import org.apache.geode.cache.configuration.CacheElement;
 import org.apache.geode.cache.configuration.ExpirationAttributesType;
 import org.apache.geode.cache.configuration.RegionAttributesDataPolicy;
+import org.apache.geode.cache.configuration.RegionAttributesScope;
 import org.apache.geode.cache.configuration.RegionAttributesType;
 import org.apache.geode.cache.configuration.RegionConfig;
 import org.apache.geode.cache.util.CacheListenerAdapter;
@@ -168,9 +169,9 @@ public class CreateRegionCommandPersistsConfigurationDUnitTest {
       RegionConfig regionConfig = regions.get(0);
       assertThat(regionConfig).isNotNull();
       assertThat(regionConfig.getName()).isEqualTo(regionName);
-      assertThat(regionConfig.getRegionAttributes()).hasSize(1);
+      assertThat(regionConfig.getRegionAttributes()).isNotNull();
 
-      RegionAttributesType attr = regionConfig.getRegionAttributes().get(0);
+      RegionAttributesType attr = regionConfig.getRegionAttributes();
       assertThat(attr.isStatisticsEnabled()).isTrue();
       assertThat(attr.isEnableAsyncConflation()).isTrue();
 
@@ -218,9 +219,9 @@ public class CreateRegionCommandPersistsConfigurationDUnitTest {
 
       assertThat(regionConfig).isNotNull();
       assertThat(regionConfig.getName()).isEqualTo(regionName);
-      assertThat(regionConfig.getRegionAttributes()).hasSize(1);
+      assertThat(regionConfig.getRegionAttributes()).isNotNull();
 
-      RegionAttributesType attr = regionConfig.getRegionAttributes().get(0);
+      RegionAttributesType attr = regionConfig.getRegionAttributes();
       assertThat(attr.isStatisticsEnabled()).isTrue();
       assertThat(attr.isEnableAsyncConflation()).isTrue();
 
@@ -277,11 +278,9 @@ public class CreateRegionCommandPersistsConfigurationDUnitTest {
         RegionConfig regionConfig = CacheElement.findElement(config.getRegions(), name);
         assertThat(regionConfig).isNotNull();
         assertThat(regionConfig.getName()).isEqualTo(name);
-        assertThat(regionConfig.getRegionAttributes())
-            .describedAs("Expecting region attributes to exist")
-            .hasSize(1);
+        assertThat(regionConfig.getRegionAttributes()).isNotNull();
 
-        RegionAttributesType attr = regionConfig.getRegionAttributes().get(0);
+        RegionAttributesType attr = regionConfig.getRegionAttributes();
         assertThat(attr.getCacheListeners().get(0).toString())
             .describedAs("Expecting one cache listener for region " + name)
             .isEqualTo(DummyCacheListener.class.getName());
@@ -389,11 +388,9 @@ public class CreateRegionCommandPersistsConfigurationDUnitTest {
         RegionConfig regionConfig = CacheElement.findElement(config.getRegions(), name);
         assertThat(regionConfig).isNotNull();
         assertThat(regionConfig.getName()).isEqualTo(name);
-        assertThat(regionConfig.getRegionAttributes())
-            .describedAs("Expecting region attributes to exist")
-            .hasSize(1);
+        assertThat(regionConfig.getRegionAttributes()).isNotNull();
 
-        RegionAttributesType attr = regionConfig.getRegionAttributes().get(0);
+        RegionAttributesType attr = regionConfig.getRegionAttributes();
         assertThat(attr.getEvictionAttributes())
             .describedAs("Eviction attributes should be null for " + name)
             .isNull();
@@ -425,7 +422,7 @@ public class CreateRegionCommandPersistsConfigurationDUnitTest {
       assertThat(regions).isNotEmpty();
       assertThat(regions).hasSize(1);
       RegionConfig regionConfig = CacheElement.findElement(regions, regionName);
-      assertThat(regionConfig.getRegionAttributes().get(0).getAsyncEventQueueIds())
+      assertThat(regionConfig.getRegionAttributes().getAsyncEventQueueIds())
           .contains(queueId);
     });
   }
@@ -459,13 +456,13 @@ public class CreateRegionCommandPersistsConfigurationDUnitTest {
 
       RegionConfig colocatedConfig = CacheElement.findElement(regions, colocatedRegionName);
       assertThat(
-          colocatedConfig.getRegionAttributes().get(0).getPartitionAttributes().getColocatedWith())
+          colocatedConfig.getRegionAttributes().getPartitionAttributes().getColocatedWith())
               .isEqualTo("/" + regionName);
 
       RegionConfig colocatedConfigFromTemplate = CacheElement.findElement(regions,
           colocatedRegionFromTemplateName);
       assertThat(
-          colocatedConfigFromTemplate.getRegionAttributes().get(0).getPartitionAttributes()
+          colocatedConfigFromTemplate.getRegionAttributes().getPartitionAttributes()
               .getColocatedWith())
                   .isEqualTo("/" + regionName);
     });
@@ -508,7 +505,7 @@ public class CreateRegionCommandPersistsConfigurationDUnitTest {
         assertThat(regionConfig).isNotNull();
         assertThat(regionConfig.getName()).isEqualTo(name);
 
-        RegionAttributesType regionAttributes = regionConfig.getRegionAttributes().get(0);
+        RegionAttributesType regionAttributes = regionConfig.getRegionAttributes();
         assertThat(regionAttributes.getDiskStoreName())
             .isEqualTo(store);
         assertThat(regionAttributes.isDiskSynchronous())
@@ -550,7 +547,7 @@ public class CreateRegionCommandPersistsConfigurationDUnitTest {
         assertThat(regionConfig).isNotNull();
         assertThat(regionConfig.getName()).isEqualTo(name);
 
-        RegionAttributesType regionAttributes = regionConfig.getRegionAttributes().get(0);
+        RegionAttributesType regionAttributes = regionConfig.getRegionAttributes();
         RegionAttributesType.PartitionAttributes partitionAttributes =
             regionAttributes.getPartitionAttributes();
 
@@ -598,7 +595,7 @@ public class CreateRegionCommandPersistsConfigurationDUnitTest {
       assertThat(regionConfig).isNotNull();
       assertThat(regionConfig.getName()).isEqualTo(regionName);
 
-      RegionAttributesType regionAttributes = regionConfig.getRegionAttributes().get(0);
+      RegionAttributesType regionAttributes = regionConfig.getRegionAttributes();
       RegionAttributesType.PartitionAttributes partitionAttributes =
           regionAttributes.getPartitionAttributes();
 
@@ -633,11 +630,9 @@ public class CreateRegionCommandPersistsConfigurationDUnitTest {
           CacheElement.findElement(config.getRegions(), regionFromTemplateName);
       assertThat(regionConfig).isNotNull();
       assertThat(regionConfig.getName()).isEqualTo(regionFromTemplateName);
-      assertThat(regionConfig.getRegionAttributes())
-          .describedAs("Expecting region attributes to exist")
-          .hasSize(1);
+      assertThat(regionConfig.getRegionAttributes()).isNotNull();
 
-      RegionAttributesType attr = regionConfig.getRegionAttributes().get(0);
+      RegionAttributesType attr = regionConfig.getRegionAttributes();
       assertThat(attr.getPartitionAttributes())
           .describedAs("Partition attributes should be null for " + regionFromTemplateName)
           .isNull();
@@ -664,11 +659,9 @@ public class CreateRegionCommandPersistsConfigurationDUnitTest {
           CacheElement.findElement(config.getRegions(), regionName);
       assertThat(regionConfig).isNotNull();
       assertThat(regionConfig.getName()).isEqualTo(regionName);
-      assertThat(regionConfig.getRegionAttributes())
-          .describedAs("Expecting region attributes to exist")
-          .hasSize(1);
+      assertThat(regionConfig.getRegionAttributes()).isNotNull();
 
-      RegionAttributesType attr = regionConfig.getRegionAttributes().get(0);
+      RegionAttributesType attr = regionConfig.getRegionAttributes();
       assertThat(attr.getRegionTimeToLive())
           .describedAs("Expiration attributes should be null for " + regionName)
           .isNull();
@@ -712,11 +705,9 @@ public class CreateRegionCommandPersistsConfigurationDUnitTest {
         RegionConfig regionConfig = CacheElement.findElement(config.getRegions(), name);
         assertThat(regionConfig).isNotNull();
         assertThat(regionConfig.getName()).isEqualTo(name);
-        assertThat(regionConfig.getRegionAttributes())
-            .describedAs("Expecting region attributes to exist for " + name)
-            .hasSize(1);
+        assertThat(regionConfig.getRegionAttributes()).isNotNull();
 
-        RegionAttributesType attr = regionConfig.getRegionAttributes().get(0);
+        RegionAttributesType attr = regionConfig.getRegionAttributes();
         assertThat(attr.isCloningEnabled())
             .describedAs("Cloning should be disabled for " + name)
             .isFalse();
@@ -746,10 +737,8 @@ public class CreateRegionCommandPersistsConfigurationDUnitTest {
       RegionConfig regionConfig = CacheElement.findElement(config.getRegions(), regionName);
       assertThat(regionConfig).isNotNull();
       assertThat(regionConfig.getName()).isEqualTo(regionName);
-      assertThat(regionConfig.getRegionAttributes())
-          .describedAs("Expecting region attributes to exist for " + regionName)
-          .hasSize(1);
-      RegionAttributesType attr = regionConfig.getRegionAttributes().get(0);
+      assertThat(regionConfig.getRegionAttributes()).isNotNull();
+      RegionAttributesType attr = regionConfig.getRegionAttributes();
       assertThat(attr.getEntryIdleTime().getExpirationAttributes().getCustomExpiry().toString())
           .describedAs("Entry expiration custom expiration should be DummyCustomExpiry")
           .isEqualTo(DummyCustomExpiry.class.getName());
@@ -757,7 +746,7 @@ public class CreateRegionCommandPersistsConfigurationDUnitTest {
   }
 
   @Test
-  public void createRegionPersistsImplicitTemplateAttributes() {
+  public void createRegionPersistsDataPolicy() {
     String regionName = testName.getMethodName();
     gfsh.executeAndAssertThat("create region"
         + " --name=" + regionName
@@ -776,14 +765,57 @@ public class CreateRegionCommandPersistsConfigurationDUnitTest {
       RegionConfig regionConfig = CacheElement.findElement(config.getRegions(), regionName);
       assertThat(regionConfig).isNotNull();
       assertThat(regionConfig.getName()).isEqualTo(regionName);
-      assertThat(regionConfig.getRegionAttributes())
-          .describedAs("Expecting region attributes to exist for " + regionName)
-          .hasSize(1);
+      assertThat(regionConfig.getRegionAttributes()).isNotNull();
 
-      RegionAttributesType attr = regionConfig.getRegionAttributes().get(0);
+      RegionAttributesType attr = regionConfig.getRegionAttributes();
       assertThat(attr.getDataPolicy())
           .describedAs("Data policy for partitioned region should be persisted correctly")
           .isEqualTo(RegionAttributesDataPolicy.PARTITION);
     });
   }
+
+  @Test
+  public void createRegionPersistsScope() {
+    String regionName = testName.getMethodName();
+    String regionName2 = regionName + "2";
+    gfsh.executeAndAssertThat("create region"
+        + " --name=" + regionName
+        + " --type=PARTITION")
+        .statusIsSuccess();
+    gfsh.executeAndAssertThat("create region"
+        + " --name=" + regionName2
+        + " --type=REPLICATE")
+        .statusIsSuccess();
+
+    locator.invoke(() -> {
+      InternalConfigurationPersistenceService cc =
+          ClusterStartupRule.getLocator().getConfigurationPersistenceService();
+      CacheConfig config = cc.getCacheConfig("cluster");
+
+      List<RegionConfig> regions = config.getRegions();
+      assertThat(regions).isNotEmpty();
+      assertThat(regions).hasSize(2);
+
+      RegionConfig regionConfig1 = CacheElement.findElement(config.getRegions(), regionName);
+      assertThat(regionConfig1).isNotNull();
+      assertThat(regionConfig1.getName()).isEqualTo(regionName);
+      assertThat(regionConfig1.getRegionAttributes()).isNotNull();
+
+      RegionAttributesType attr1 = regionConfig1.getRegionAttributes();
+      assertThat(attr1.getScope())
+          .describedAs("Scope for partitioned region should be null")
+          .isNull();
+
+      RegionConfig regionConfig2 = CacheElement.findElement(config.getRegions(), regionName2);
+      assertThat(regionConfig2).isNotNull();
+      assertThat(regionConfig2.getName()).isEqualTo(regionName2);
+      assertThat(regionConfig2.getRegionAttributes()).isNotNull();
+
+      RegionAttributesType attr2 = regionConfig2.getRegionAttributes();
+      assertThat(attr2.getScope())
+          .describedAs(
+              "Scope for replicated region should be persisted as distributed-ack by default")
+          .isEqualTo(RegionAttributesScope.DISTRIBUTED_ACK);
+    });
+  }
 }
diff --git a/geode-core/src/distributedTest/java/org/apache/geode/management/internal/cli/commands/DestroyRegionCommandDUnitTest.java b/geode-core/src/distributedTest/java/org/apache/geode/management/internal/cli/commands/DestroyRegionCommandDUnitTest.java
index 0849ba3..511fe14 100644
--- a/geode-core/src/distributedTest/java/org/apache/geode/management/internal/cli/commands/DestroyRegionCommandDUnitTest.java
+++ b/geode-core/src/distributedTest/java/org/apache/geode/management/internal/cli/commands/DestroyRegionCommandDUnitTest.java
@@ -117,13 +117,14 @@ public class DestroyRegionCommandDUnitTest {
       Configuration group1Config = service.getConfiguration("group1");
       assertThat(group1Config.getCacheXmlContent())
           .containsOnlyOnce("<region name=\"region1\">")
-          .containsOnlyOnce("<region-attributes data-policy=\"empty\" scope=\"distributed-ack\"/>");
+          .containsOnlyOnce("data-policy=\"empty\"")
+          .containsOnlyOnce("scope=\"distributed-ack\"");
 
       Configuration clusterConfig = service.getConfiguration("group2");
       assertThat(clusterConfig.getCacheXmlContent())
           .containsOnlyOnce("<region name=\"region1\">")
-          .containsOnlyOnce(
-              "<region-attributes data-policy=\"replicate\" scope=\"distributed-ack\"/>");
+          .containsOnlyOnce("data-policy=\"replicate\"")
+          .containsOnlyOnce("scope=\"distributed-ack\"");
     });
 
     gfsh.executeAndAssertThat("destroy region --name=region1").statusIsSuccess()
diff --git a/geode-core/src/main/java/org/apache/geode/cache/Scope.java b/geode-core/src/main/java/org/apache/geode/cache/Scope.java
index 604f6a7..7517f56 100644
--- a/geode-core/src/main/java/org/apache/geode/cache/Scope.java
+++ b/geode-core/src/main/java/org/apache/geode/cache/Scope.java
@@ -157,6 +157,10 @@ public class Scope implements Serializable {
     return this.name;
   }
 
+  public String toConfigTypeString() {
+    return this.name.toLowerCase().replace("_", "-");
+  }
+
   /**
    * Parse the given string into a Scope
    *
diff --git a/geode-core/src/main/java/org/apache/geode/cache/configuration/RegionConfig.java b/geode-core/src/main/java/org/apache/geode/cache/configuration/RegionConfig.java
index 8dbb387..2638ecf 100644
--- a/geode-core/src/main/java/org/apache/geode/cache/configuration/RegionConfig.java
+++ b/geode-core/src/main/java/org/apache/geode/cache/configuration/RegionConfig.java
@@ -28,8 +28,6 @@ import javax.xml.bind.annotation.XmlAttribute;
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlType;
 
-import org.w3c.dom.Element;
-
 import org.apache.geode.annotations.Experimental;
 
 
@@ -151,9 +149,8 @@ import org.apache.geode.annotations.Experimental;
     propOrder = {"regionAttributes", "indexes", "entries", "regionElements", "regions"})
 @Experimental
 public class RegionConfig implements CacheElement {
-
   @XmlElement(name = "region-attributes", namespace = "http://geode.apache.org/schema/cache")
-  protected List<RegionAttributesType> regionAttributes;
+  protected RegionAttributesType regionAttributes;
   @XmlElement(name = "index", namespace = "http://geode.apache.org/schema/cache")
   protected List<RegionConfig.Index> indexes;
   @XmlElement(name = "entry", namespace = "http://geode.apache.org/schema/cache")
@@ -174,34 +171,12 @@ public class RegionConfig implements CacheElement {
     this.refid = refid;
   }
 
-  /**
-   * Gets the value of the regionAttributes property.
-   *
-   * <p>
-   * This accessor method returns a reference to the live list,
-   * not a snapshot. Therefore any modification you make to the
-   * returned list will be present inside the JAXB object.
-   * This is why there is not a <CODE>set</CODE> method for the regionAttributes property.
-   *
-   * <p>
-   * For example, to add a new item, do as follows:
-   *
-   * <pre>
-   * getRegionAttributes().add(newItem);
-   * </pre>
-   *
-   *
-   * <p>
-   * Objects of the following type(s) are allowed in the list
-   * {@link RegionAttributesType }
-   *
-   *
-   */
-  public List<RegionAttributesType> getRegionAttributes() {
-    if (regionAttributes == null) {
-      regionAttributes = new ArrayList<RegionAttributesType>();
-    }
-    return this.regionAttributes;
+  public RegionAttributesType getRegionAttributes() {
+    return regionAttributes;
+  }
+
+  public void setRegionAttributes(RegionAttributesType regionAttributes) {
+    this.regionAttributes = regionAttributes;
   }
 
   /**
@@ -229,7 +204,7 @@ public class RegionConfig implements CacheElement {
    */
   public List<RegionConfig.Index> getIndexes() {
     if (indexes == null) {
-      indexes = new ArrayList<RegionConfig.Index>();
+      indexes = new ArrayList<>();
     }
     return this.indexes;
   }
@@ -283,10 +258,6 @@ public class RegionConfig implements CacheElement {
    *
    * <p>
    * Objects of the following type(s) are allowed in the list
-   * {@link Element }
-   * {@link CacheElement }
-   *
-   *
    */
   public List<CacheElement> getCustomRegionElements() {
     if (regionElements == null) {
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/domain/RegionAttributeGetFunction.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/domain/RegionAttributeGetFunction.java
deleted file mode 100644
index ebee2db..0000000
--- a/geode-core/src/main/java/org/apache/geode/management/internal/cli/domain/RegionAttributeGetFunction.java
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * 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 org.apache.geode.cache.configuration.RegionAttributesType;
-
-@FunctionalInterface
-public interface RegionAttributeGetFunction {
-  Object getValue(RegionAttributesType attributesType);
-}
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/domain/RegionAttributeSetFunction.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/domain/RegionAttributeSetFunction.java
deleted file mode 100644
index 051e815..0000000
--- a/geode-core/src/main/java/org/apache/geode/management/internal/cli/domain/RegionAttributeSetFunction.java
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * 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 org.apache.geode.cache.configuration.RegionAttributesType;
-
-@FunctionalInterface
-public interface RegionAttributeSetFunction {
-  void setAttributeValue(RegionAttributesType attributesType);
-}
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/domain/RegionConfigFactory.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/domain/RegionConfigFactory.java
index 59a01a7..39df779 100644
--- a/geode-core/src/main/java/org/apache/geode/management/internal/cli/domain/RegionConfigFactory.java
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/domain/RegionConfigFactory.java
@@ -14,14 +14,16 @@
  */
 package org.apache.geode.management.internal.cli.domain;
 
-import java.util.List;
 import java.util.Optional;
+import java.util.function.Consumer;
+import java.util.function.Function;
 import java.util.stream.Collectors;
 
 import org.apache.geode.cache.RegionAttributes;
 import org.apache.geode.cache.configuration.ClassNameType;
 import org.apache.geode.cache.configuration.DeclarableType;
 import org.apache.geode.cache.configuration.ExpirationAttributesType;
+import org.apache.geode.cache.configuration.RegionAttributesScope;
 import org.apache.geode.cache.configuration.RegionAttributesType;
 import org.apache.geode.cache.configuration.RegionConfig;
 import org.apache.geode.management.internal.cli.functions.RegionFunctionArgs;
@@ -62,7 +64,7 @@ public class RegionConfigFactory {
     }
 
     if (args.getEntryIdleTimeCustomExpiry() != null) {
-      Object maybeEntryIdleAttr = getRegionAttributeValue(regionConfig, a -> a.getEntryIdleTime());
+      Object maybeEntryIdleAttr = getAttribute(regionConfig, a -> a.getEntryIdleTime());
       RegionAttributesType.EntryIdleTime entryIdleTime =
           maybeEntryIdleAttr != null ? (RegionAttributesType.EntryIdleTime) maybeEntryIdleAttr
               : new RegionAttributesType.EntryIdleTime();
@@ -134,7 +136,7 @@ public class RegionConfigFactory {
     }
 
     if (args.getEntryTTLCustomExpiry() != null) {
-      Object maybeEntryTTLAttr = getRegionAttributeValue(regionConfig, a -> a.getEntryTimeToLive());
+      Object maybeEntryTTLAttr = getAttribute(regionConfig, a -> a.getEntryTimeToLive());
       RegionAttributesType.EntryTimeToLive entryTimeToLive =
           maybeEntryTTLAttr != null ? (RegionAttributesType.EntryTimeToLive) maybeEntryTTLAttr
               : new RegionAttributesType.EntryTimeToLive();
@@ -295,6 +297,13 @@ public class RegionConfigFactory {
           a -> a.setDataPolicy(regionAttributes.getDataPolicy().toConfigType()));
     }
 
+    if (regionAttributes != null && regionAttributes.getScope() != null
+        && !regionAttributes.getDataPolicy().withPartitioning()) {
+      addAttribute(regionConfig,
+          a -> a.setScope(
+              RegionAttributesScope.fromValue(regionAttributes.getScope().toConfigTypeString())));
+    }
+
     return regionConfig;
   }
 
@@ -313,19 +322,20 @@ public class RegionConfigFactory {
     return regions[regions.length - 1];
   }
 
-  private void addAttribute(RegionConfig config, RegionAttributeSetFunction func) {
-    final List<RegionAttributesType> regionAttributes = config.getRegionAttributes();
-    if (regionAttributes.isEmpty()) {
-      regionAttributes.add(new RegionAttributesType());
+  private void addAttribute(RegionConfig config, Consumer<RegionAttributesType> consumer) {
+    if (config.getRegionAttributes() == null) {
+      config.setRegionAttributes(new RegionAttributesType());
     }
 
-    func.setAttributeValue(regionAttributes.get(0));
+    consumer.accept(config.getRegionAttributes());
   }
 
-  private Object getRegionAttributeValue(RegionConfig config, RegionAttributeGetFunction function) {
-    return config.getRegionAttributes().stream()
-        .findFirst()
-        .map(a -> function.getValue(a))
-        .orElse(null);
+  private Object getAttribute(RegionConfig config,
+      Function<RegionAttributesType, Object> function) {
+    if (config.getRegionAttributes() == null) {
+      return null;
+    }
+
+    return function.apply(config.getRegionAttributes());
   }
 }
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 353ee30..9dfa16d 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
@@ -37,7 +37,6 @@ import org.apache.geode.cache.Region;
 import org.apache.geode.cache.RegionAttributes;
 import org.apache.geode.cache.RegionExistsException;
 import org.apache.geode.cache.RegionFactory;
-import org.apache.geode.cache.RegionShortcut;
 import org.apache.geode.cache.execute.FunctionContext;
 import org.apache.geode.cache.execute.ResultSender;
 import org.apache.geode.cache.util.ObjectSizer;
@@ -45,14 +44,12 @@ import org.apache.geode.compression.Compressor;
 import org.apache.geode.internal.ClassPathLoader;
 import org.apache.geode.internal.cache.InternalCache;
 import org.apache.geode.internal.cache.execute.InternalFunction;
-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.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;
 
 /**
  *
@@ -141,20 +138,9 @@ public class RegionCreateFunction implements InternalFunction {
     return new CliFunctionResult(memberNameOrId, CliFunctionResult.StatusState.ERROR);
   }
 
-  private XmlEntity getXmlEntityForRegion(Region<?, ?> region) {
-    Region<?, ?> curRegion = region;
-    while (curRegion != null && curRegion.getParentRegion() != null) {
-      curRegion = curRegion.getParentRegion();
-    }
-
-    return new XmlEntity(CacheXml.REGION, "name", curRegion.getName());
-  }
-
   private <K, V> Region<?, ?> createRegion(Cache cache, RegionFunctionArgs regionCreateArgs) {
     Region<K, V> createdRegion = null;
 
-    final RegionShortcut regionShortcut = regionCreateArgs.getRegionShortcut();
-
     // create the region factory using the arguments
     RegionAttributes<K, V> regionAttributes = regionCreateArgs.getRegionAttributes();
     boolean isPartitioned = regionAttributes.getPartitionAttributes() != null;
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 cf04eb9..2ed61b6 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
@@ -136,7 +136,7 @@ org/apache/geode/cache/configuration/RegionAttributesMirrorType,false,value:java
 org/apache/geode/cache/configuration/RegionAttributesScope,false,value:java/lang/String
 org/apache/geode/cache/configuration/RegionAttributesType$EvictionAttributes$LruHeapPercentage,false,action:org/apache/geode/cache/configuration/EnumActionDestroyOverflow
 org/apache/geode/cache/configuration/RegionAttributesType$EvictionAttributes$LruMemorySize,false,maximum:java/lang/String
-org/apache/geode/cache/configuration/RegionConfig,false,entries:java/util/List,indexes:java/util/List,name:java/lang/String,refid:java/lang/String,regionAttributes:java/util/List,regionElements:java/util/List,regions:java/util/List
+org/apache/geode/cache/configuration/RegionConfig,false,entries:java/util/List,indexes:java/util/List,name:java/lang/String,refid:java/lang/String,regionAttributes:org/apache/geode/cache/configuration/RegionAttributesType,regionElements:java/util/List,regions:java/util/List
 org/apache/geode/cache/configuration/RegionConfig$Index,false,expression:java/lang/String,fromClause:java/lang/String,imports:java/lang/String,keyIndex:java/lang/Boolean,name:java/lang/String,type:java/lang/String
 org/apache/geode/cache/execute/EmptyRegionFunctionException,true,1
 org/apache/geode/cache/execute/FunctionAdapter,true,-4891043890440825485
diff --git a/geode-core/src/test/java/org/apache/geode/cache/configuration/CacheConfigTest.java b/geode-core/src/test/java/org/apache/geode/cache/configuration/CacheConfigTest.java
index 056e544..b15a95d 100644
--- a/geode-core/src/test/java/org/apache/geode/cache/configuration/CacheConfigTest.java
+++ b/geode-core/src/test/java/org/apache/geode/cache/configuration/CacheConfigTest.java
@@ -166,4 +166,22 @@ public class CacheConfigTest {
     assertThat(regionAttributes.getRegionTimeToLive().getExpirationAttributes().getCustomExpiry())
         .isEqualTo(declarableWithString);
   }
+
+  @Test
+  public void regionConfig() {
+    cacheConfig = new CacheConfig("1.0");
+    RegionConfig regionConfig = new RegionConfig();
+    regionConfig.setName("test");
+    regionConfig.setRefid("REPLICATE");
+    RegionAttributesType attributes = new RegionAttributesType();
+    attributes.setCacheLoader(new DeclarableType("abc.Foo"));
+    regionConfig.setRegionAttributes(attributes);
+    cacheConfig.getRegions().add(regionConfig);
+
+    // make sure the xml marshed by this config can be validated with xsd
+    String xml = service.marshall(cacheConfig);
+
+    CacheConfig newCache = service.unMarshall(xml);
+    assertThat(cacheConfig).isEqualToComparingFieldByFieldRecursively(newCache);
+  }
 }
diff --git a/geode-core/src/test/java/org/apache/geode/management/internal/cli/domain/RegionConfigFactoryTest.java b/geode-core/src/test/java/org/apache/geode/management/internal/cli/domain/RegionConfigFactoryTest.java
index 31b5bd9..4eec7e5 100644
--- a/geode-core/src/test/java/org/apache/geode/management/internal/cli/domain/RegionConfigFactoryTest.java
+++ b/geode-core/src/test/java/org/apache/geode/management/internal/cli/domain/RegionConfigFactoryTest.java
@@ -23,7 +23,6 @@ import org.junit.Test;
 
 import org.apache.geode.cache.EvictionAction;
 import org.apache.geode.cache.ExpirationAction;
-import org.apache.geode.cache.configuration.ClassNameType;
 import org.apache.geode.cache.configuration.DeclarableType;
 import org.apache.geode.cache.configuration.EnumActionDestroyOverflow;
 import org.apache.geode.cache.configuration.RegionAttributesType;
@@ -57,9 +56,9 @@ public class RegionConfigFactoryTest {
   }
 
   @Test
-  public void generatesWithNoAttributes() {
+  public void generatesNullWithNoAttributes() {
     RegionConfig config = subject.generate(args);
-    assertThat(config.getRegionAttributes()).isEmpty();
+    assertThat(config.getRegionAttributes()).isNull();
   }
 
   @Test
@@ -68,8 +67,8 @@ public class RegionConfigFactoryTest {
     args.setValueConstraint("value-const");
 
     RegionConfig config = subject.generate(args);
-    assertThat(getRegionAttributeValue(config, t -> t.getKeyConstraint())).isEqualTo("key-const");
-    assertThat(getRegionAttributeValue(config, t -> t.getValueConstraint()))
+    assertThat(config.getRegionAttributes().getKeyConstraint()).isEqualTo("key-const");
+    assertThat(config.getRegionAttributes().getValueConstraint())
         .isEqualTo("value-const");
   }
 
@@ -83,19 +82,16 @@ public class RegionConfigFactoryTest {
 
     RegionConfig config = subject.generate(args);
     RegionAttributesType.RegionTimeToLive regionTimeToLive =
-        (RegionAttributesType.RegionTimeToLive) getRegionAttributeValue(config,
-            t -> t.getRegionTimeToLive());
+        config.getRegionAttributes().getRegionTimeToLive();
     assertThat(regionTimeToLive.getExpirationAttributes().getTimeout()).isEqualTo("10");
 
     RegionAttributesType.EntryTimeToLive entryTimeToLive =
-        (RegionAttributesType.EntryTimeToLive) getRegionAttributeValue(config,
-            t -> t.getEntryTimeToLive());
+        config.getRegionAttributes().getEntryTimeToLive();
     assertThat(entryTimeToLive.getExpirationAttributes().getAction())
         .isEqualTo(ExpirationAction.LOCAL_DESTROY.toXmlString());
 
     RegionAttributesType.EntryIdleTime entryIdleTime =
-        (RegionAttributesType.EntryIdleTime) getRegionAttributeValue(config,
-            t -> t.getEntryIdleTime());
+        config.getRegionAttributes().getEntryIdleTime();
     DeclarableType customExpiry = entryIdleTime.getExpirationAttributes().getCustomExpiry();
     assertThat(customExpiry.getClassName()).isEqualTo("java.lang.String");
     assertThat(entryIdleTime.getExpirationAttributes().getAction())
@@ -110,8 +106,8 @@ public class RegionConfigFactoryTest {
     args.setDiskSynchronous(false);
 
     RegionConfig config = subject.generate(args);
-    assertThat(getRegionAttributeValue(config, t -> t.getDiskStoreName())).isEqualTo("disk-store");
-    assertThat(getRegionAttributeValue(config, t -> t.isDiskSynchronous())).isEqualTo(false);
+    assertThat(config.getRegionAttributes().getDiskStoreName()).isEqualTo("disk-store");
+    assertThat(config.getRegionAttributes().isDiskSynchronous()).isEqualTo(false);
   }
 
   @Test
@@ -122,8 +118,7 @@ public class RegionConfigFactoryTest {
 
     RegionConfig config = subject.generate(args);
     RegionAttributesType.PartitionAttributes partitionAttributes =
-        (RegionAttributesType.PartitionAttributes) getRegionAttributeValue(config,
-            t -> t.getPartitionAttributes());
+        config.getRegionAttributes().getPartitionAttributes();
     assertThat(partitionAttributes).isNotNull();
     assertThat(partitionAttributes.getColocatedWith()).isEqualTo("colo-with");
     assertThat(partitionAttributes.getLocalMaxMemory()).isEqualTo("100");
@@ -148,17 +143,17 @@ public class RegionConfigFactoryTest {
     args.setOffHeap(true);
     RegionConfig config = subject.generate(args);
 
-    assertThat(getRegionAttributeValue(config, t -> t.isStatisticsEnabled())).isEqualTo(false);
-    assertThat(getRegionAttributeValue(config, t -> t.isEnableSubscriptionConflation()))
+    assertThat(config.getRegionAttributes().isStatisticsEnabled()).isEqualTo(false);
+    assertThat(config.getRegionAttributes().isEnableSubscriptionConflation())
         .isEqualTo(true);
-    assertThat(getRegionAttributeValue(config, t -> t.isConcurrencyChecksEnabled()))
+    assertThat(config.getRegionAttributes().isConcurrencyChecksEnabled())
         .isEqualTo(true);
-    assertThat(getRegionAttributeValue(config, t -> t.isEnableSubscriptionConflation()))
+    assertThat(config.getRegionAttributes().isEnableSubscriptionConflation())
         .isEqualTo(true);
-    assertThat(getRegionAttributeValue(config, t -> t.isMulticastEnabled()))
+    assertThat(config.getRegionAttributes().isMulticastEnabled())
         .isEqualTo(false);
-    assertThat(getRegionAttributeValue(config, t -> t.isCloningEnabled())).isEqualTo(false);
-    assertThat(getRegionAttributeValue(config, t -> t.isOffHeap())).isEqualTo(true);
+    assertThat(config.getRegionAttributes().isCloningEnabled()).isEqualTo(false);
+    assertThat(config.getRegionAttributes().isOffHeap()).isEqualTo(true);
   }
 
   @Test
@@ -166,9 +161,9 @@ public class RegionConfigFactoryTest {
     args.setGatewaySenderIds(new String[] {"some-id", "some-other-id"});
     RegionConfig config = subject.generate(args);
 
-    assertThat((String) getRegionAttributeValue(config, t -> t.getGatewaySenderIds()))
+    assertThat(config.getRegionAttributes().getGatewaySenderIds())
         .contains("some-id");
-    assertThat((String) getRegionAttributeValue(config, t -> t.getGatewaySenderIds()))
+    assertThat(config.getRegionAttributes().getGatewaySenderIds())
         .contains("some-other-id");
   }
 
@@ -179,8 +174,7 @@ public class RegionConfigFactoryTest {
     RegionConfig config = subject.generate(args);
 
     RegionAttributesType.EvictionAttributes evictionAttributes =
-        (RegionAttributesType.EvictionAttributes) getRegionAttributeValue(config,
-            t -> t.getEvictionAttributes());
+        config.getRegionAttributes().getEvictionAttributes();
     assertThat(evictionAttributes).isNotNull();
     assertThat(evictionAttributes.getLruHeapPercentage().getAction())
         .isSameAs(EnumActionDestroyOverflow.LOCAL_DESTROY);
@@ -195,8 +189,7 @@ public class RegionConfigFactoryTest {
     RegionConfig config = subject.generate(args);
 
     RegionAttributesType.EvictionAttributes evictionAttributes =
-        (RegionAttributesType.EvictionAttributes) getRegionAttributeValue(config,
-            t -> t.getEvictionAttributes());
+        config.getRegionAttributes().getEvictionAttributes();
     assertThat(evictionAttributes).isNotNull();
     assertThat(evictionAttributes.getLruMemorySize().getAction())
         .isSameAs(EnumActionDestroyOverflow.LOCAL_DESTROY);
@@ -209,8 +202,7 @@ public class RegionConfigFactoryTest {
         null);
     RegionConfig config = subject.generate(args);
     RegionAttributesType.EvictionAttributes evictionAttributes =
-        (RegionAttributesType.EvictionAttributes) getRegionAttributeValue(config,
-            t -> t.getEvictionAttributes());
+        config.getRegionAttributes().getEvictionAttributes();
     assertThat(evictionAttributes).isNotNull();
     assertThat(evictionAttributes.getLruEntryCount().getAction())
         .isSameAs(EnumActionDestroyOverflow.OVERFLOW_TO_DISK);
@@ -222,9 +214,9 @@ public class RegionConfigFactoryTest {
     args.setAsyncEventQueueIds(new String[] {"id-1", "id-2"});
     RegionConfig config = subject.generate(args);
 
-    assertThat((String) getRegionAttributeValue(config, t -> t.getAsyncEventQueueIds()))
+    assertThat(config.getRegionAttributes().getAsyncEventQueueIds())
         .contains("id-1");
-    assertThat((String) getRegionAttributeValue(config, t -> t.getAsyncEventQueueIds()))
+    assertThat(config.getRegionAttributes().getAsyncEventQueueIds())
         .contains("id-2");
   }
 
@@ -235,19 +227,15 @@ public class RegionConfigFactoryTest {
     args.setCacheWriter(new ClassName("java.lang.String"));
     RegionConfig config = subject.generate(args);
 
-    List<DeclarableType> cacheListeners = config.getRegionAttributes().stream()
-        .filter(a -> !a.getCacheListeners().isEmpty())
-        .findFirst()
-        .map(a -> a.getCacheListeners())
-        .orElse(null);
+    List<DeclarableType> cacheListeners = config.getRegionAttributes().getCacheListeners();
 
     assertThat(cacheListeners).isNotNull();
     assertThat(cacheListeners.get(0).getClassName()).isEqualTo("java.lang.String");
     assertThat(
-        ((DeclarableType) getRegionAttributeValue(config, t -> t.getCacheLoader())).getClassName())
+        config.getRegionAttributes().getCacheLoader().getClassName())
             .isEqualTo("java.lang.String");
     assertThat(
-        ((DeclarableType) getRegionAttributeValue(config, t -> t.getCacheWriter())).getClassName())
+        config.getRegionAttributes().getCacheWriter().getClassName())
             .isEqualTo("java.lang.String");
   }
 
@@ -259,15 +247,9 @@ public class RegionConfigFactoryTest {
     RegionConfig config = subject.generate(args);
 
     assertThat(
-        ((ClassNameType) getRegionAttributeValue(config, t -> t.getCompressor())).getClassName())
+        config.getRegionAttributes().getCompressor().getClassName())
             .isEqualTo("java.lang.String");
-    assertThat(getRegionAttributeValue(config, t -> t.getConcurrencyLevel())).isEqualTo("1");
+    assertThat(config.getRegionAttributes().getConcurrencyLevel()).isEqualTo("1");
   }
 
-  private Object getRegionAttributeValue(RegionConfig config, RegionAttributeGetFunction function) {
-    return config.getRegionAttributes().stream()
-        .findFirst()
-        .map(a -> function.getValue(a))
-        .orElse(null);
-  }
 }