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

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


The following commit(s) were added to refs/heads/develop by this push:
     new 7c5d8d9  GEODE-7504: region eviction support (#4428)
7c5d8d9 is described below

commit 7c5d8d94777d03a30ec137f05a1b1bb2e057dee5
Author: Jinmei Liao <[email protected]>
AuthorDate: Fri Dec 6 09:07:54 2019 -0800

    GEODE-7504: region eviction support (#4428)
    
    Co-authored-by: Joris Melchior <[email protected]>
    Co-authored-by: Darrel Schneider <[email protected]>
    Co-authored-by: Jinmei Liao <[email protected]>
    
    * added eviction support to RegionConverter and RegionConfigValidator
---
 .../internal/rest/RegionManagementDunitTest.java   |  52 ++++++
 .../integrationTest/resources/assembly_content.txt |   3 +
 .../geode/util/internal/GeodeJsonMapper.java       |  11 ++
 .../geode/util/internal/GeodeJsonMapperTest.java   |  76 +++++++++
 .../geode/cache/configuration/DeclarableType.java  |  16 +-
 .../cache/configuration/RegionAttributesType.java  |  21 ++-
 .../configuration/converters/RegionConverter.java  |  80 ++++++++-
 .../validators/RegionConfigValidator.java          |  33 ++++
 .../sanctioned-geode-management-serializables.txt  |   7 +-
 .../configuration/RegionAttributesTypeTest.java    |  13 +-
 .../converters/RegionConverterTest.java            | 189 +++++++++++++++++++--
 .../validators/RegionConfigValidatorTest.java      |  98 ++++++++++-
 .../geode/management/configuration/Region.java     | 114 ++++++++++++-
 .../PlainClusterManagementServiceBuilder.java      |  14 +-
 .../geode/management/configuration/RegionTest.java |  96 ++++++++++-
 15 files changed, 785 insertions(+), 38 deletions(-)

diff --git 
a/geode-assembly/src/distributedTest/java/org/apache/geode/management/internal/rest/RegionManagementDunitTest.java
 
b/geode-assembly/src/distributedTest/java/org/apache/geode/management/internal/rest/RegionManagementDunitTest.java
index 727b7ee1..77130ac 100644
--- 
a/geode-assembly/src/distributedTest/java/org/apache/geode/management/internal/rest/RegionManagementDunitTest.java
+++ 
b/geode-assembly/src/distributedTest/java/org/apache/geode/management/internal/rest/RegionManagementDunitTest.java
@@ -27,9 +27,13 @@ import org.junit.ClassRule;
 import org.junit.Test;
 
 import org.apache.geode.cache.Cache;
+import org.apache.geode.cache.EvictionAction;
+import org.apache.geode.cache.EvictionAlgorithm;
+import org.apache.geode.cache.EvictionAttributes;
 import org.apache.geode.cache.ExpirationAction;
 import org.apache.geode.cache.RegionAttributes;
 import org.apache.geode.cache.configuration.CacheConfig;
+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.api.ClusterManagementRealizationResult;
@@ -277,4 +281,52 @@ public class RegionManagementDunitTest {
     
assertThat(expirations.get(1).getAction()).isEqualTo(Region.ExpirationAction.INVALIDATE);
     
assertThat(expirations.get(1).getType()).isEqualTo(Region.ExpirationType.ENTRY_TIME_TO_LIVE);
   }
+
+  @Test
+  public void createRegionWithEviction() {
+    Region region = new Region();
+    String regionName = "createRegionWithEviction";
+    region.setName(regionName);
+    region.setType(RegionType.REPLICATE);
+    Region.Eviction eviction = new Region.Eviction();
+    eviction.setAction(Region.EvictionAction.OVERFLOW_TO_DISK);
+    eviction.setEntryCount(100);
+    region.setEviction(eviction);
+
+    assertManagementResult(cms.create(region)).isSuccessful();
+
+    locator.invoke(() -> {
+      CacheConfig cacheConfig =
+          ClusterStartupRule.getLocator().getConfigurationPersistenceService()
+              .getCacheConfig("cluster");
+      RegionConfig regionConfig = find(cacheConfig.getRegions(), regionName);
+      RegionAttributesType regionAttributes = 
regionConfig.getRegionAttributes();
+      RegionAttributesType.EvictionAttributes evictionAttributes =
+          regionAttributes.getEvictionAttributes();
+      assertThat(evictionAttributes).isNotNull();
+      assertThat(evictionAttributes.getLruEntryCount()).isNotNull();
+      assertThat(evictionAttributes.getLruEntryCount().getAction()).isEqualTo(
+          EnumActionDestroyOverflow.OVERFLOW_TO_DISK);
+      
assertThat(evictionAttributes.getLruEntryCount().getMaximum()).isEqualTo("100");
+    });
+
+    server1.invoke(() -> {
+      Cache cache = ClusterStartupRule.getCache();
+      org.apache.geode.cache.Region actualRegion = cache.getRegion(regionName);
+      RegionAttributes attributes = actualRegion.getAttributes();
+      EvictionAttributes evictionAttributes = 
attributes.getEvictionAttributes();
+      assertThat(evictionAttributes).isNotNull();
+      
assertThat(evictionAttributes.getAlgorithm()).isEqualTo(EvictionAlgorithm.LRU_ENTRY);
+      
assertThat(evictionAttributes.getAction()).isEqualTo(EvictionAction.OVERFLOW_TO_DISK);
+      assertThat(evictionAttributes.getMaximum()).isEqualTo(100);
+
+    });
+
+    Region regionResult = cms.get(region).getConfigResult();
+    Region.Eviction eviction2 = regionResult.getEviction();
+    assertThat(eviction2).isNotNull();
+    assertThat(eviction2.getType()).isEqualTo(Region.EvictionType.ENTRY_COUNT);
+    assertThat(eviction2.getEntryCount()).isEqualTo(100);
+    
assertThat(eviction2.getAction()).isEqualTo(Region.EvictionAction.OVERFLOW_TO_DISK);
+  }
 }
diff --git a/geode-assembly/src/integrationTest/resources/assembly_content.txt 
b/geode-assembly/src/integrationTest/resources/assembly_content.txt
index 65ec8ae..3d51d75 100644
--- a/geode-assembly/src/integrationTest/resources/assembly_content.txt
+++ b/geode-assembly/src/integrationTest/resources/assembly_content.txt
@@ -746,6 +746,9 @@ javadoc/org/apache/geode/management/configuration/Index.html
 javadoc/org/apache/geode/management/configuration/Links.html
 javadoc/org/apache/geode/management/configuration/Member.html
 javadoc/org/apache/geode/management/configuration/Pdx.html
+javadoc/org/apache/geode/management/configuration/Region.Eviction.html
+javadoc/org/apache/geode/management/configuration/Region.EvictionAction.html
+javadoc/org/apache/geode/management/configuration/Region.EvictionType.html
 javadoc/org/apache/geode/management/configuration/Region.Expiration.html
 javadoc/org/apache/geode/management/configuration/Region.ExpirationAction.html
 javadoc/org/apache/geode/management/configuration/Region.ExpirationType.html
diff --git 
a/geode-common/src/main/java/org/apache/geode/util/internal/GeodeJsonMapper.java
 
b/geode-common/src/main/java/org/apache/geode/util/internal/GeodeJsonMapper.java
index 2b0b632..6b1cc77 100644
--- 
a/geode-common/src/main/java/org/apache/geode/util/internal/GeodeJsonMapper.java
+++ 
b/geode-common/src/main/java/org/apache/geode/util/internal/GeodeJsonMapper.java
@@ -15,6 +15,8 @@
 
 package org.apache.geode.util.internal;
 
+import static 
com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES;
+
 import com.fasterxml.jackson.annotation.JsonInclude;
 import com.fasterxml.jackson.core.JsonParser;
 import com.fasterxml.jackson.databind.MapperFeature;
@@ -36,4 +38,13 @@ public class GeodeJsonMapper {
     mapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);
     return mapper;
   }
+
+  public static ObjectMapper getMapperIgnoringUnknownProperties() {
+    ObjectMapper mapper = new ObjectMapper();
+    mapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
+    mapper.configure(MapperFeature.USE_BASE_TYPE_AS_DEFAULT_IMPL, true);
+    mapper.configure(FAIL_ON_UNKNOWN_PROPERTIES, false);
+    mapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);
+    return mapper;
+  }
 }
diff --git 
a/geode-common/src/test/java/org/apache/geode/util/internal/GeodeJsonMapperTest.java
 
b/geode-common/src/test/java/org/apache/geode/util/internal/GeodeJsonMapperTest.java
new file mode 100644
index 0000000..42a6e0c
--- /dev/null
+++ 
b/geode-common/src/test/java/org/apache/geode/util/internal/GeodeJsonMapperTest.java
@@ -0,0 +1,76 @@
+/*
+ * 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.util.internal;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException;
+import org.junit.Test;
+
+public class GeodeJsonMapperTest {
+  @Test
+  public void ignoreUnknownPropMapper() throws Exception {
+    ObjectMapper mapper = GeodeJsonMapper.getMapperIgnoringUnknownProperties();
+    String json = "{\"name\":\"Joe\"}";
+
+    Employee employee = new Employee();
+    employee.setName("Joe");
+    assertThat(mapper.writeValueAsString(employee)).isEqualTo(json);
+
+    String jsonWithUnknownProp = "{\"name\":\"Joe\",\"id\":\"test\"}";
+    employee = mapper.readValue(jsonWithUnknownProp, Employee.class);
+    assertThat(employee.getName()).isEqualTo("Joe");
+    assertThat(employee.getTitle()).isNull();
+  }
+
+  @Test
+  public void regularMapper() throws Exception {
+    ObjectMapper mapper = GeodeJsonMapper.getMapper();
+    String json = "{\"name\":\"Joe\"}";
+
+    Employee employee = new Employee();
+    employee.setName("Joe");
+    assertThat(mapper.writeValueAsString(employee)).isEqualTo(json);
+
+    String jsonWithUnknownProp = "{\"name\":\"Joe\",\"id\":\"test\"}";
+    assertThatThrownBy(() -> mapper.readValue(jsonWithUnknownProp, 
Employee.class))
+        .isInstanceOf(UnrecognizedPropertyException.class)
+        .hasMessageContaining("Unrecognized field \"id\"");
+  }
+
+  private static class Employee {
+    private String name;
+    private String title;
+
+    public String getName() {
+      return name;
+    }
+
+    public void setName(String name) {
+      this.name = name;
+    }
+
+    public String getTitle() {
+      return title;
+    }
+
+    public void setTitle(String title) {
+      this.title = title;
+    }
+  }
+}
diff --git 
a/geode-core/src/main/java/org/apache/geode/cache/configuration/DeclarableType.java
 
b/geode-core/src/main/java/org/apache/geode/cache/configuration/DeclarableType.java
index 3670c5b..2702fd2 100644
--- 
a/geode-core/src/main/java/org/apache/geode/cache/configuration/DeclarableType.java
+++ 
b/geode-core/src/main/java/org/apache/geode/cache/configuration/DeclarableType.java
@@ -85,11 +85,7 @@ public class DeclarableType extends ClassNameType implements 
Serializable {
     }
 
     this.className = className;
-
-    if (properties != null) {
-      parameters = properties.stringPropertyNames().stream()
-          .map(k -> new ParameterType(k, 
properties.getProperty(k))).collect(Collectors.toList());
-    }
+    setParameters(properties);
   }
 
   /**
@@ -118,6 +114,16 @@ public class DeclarableType extends ClassNameType 
implements Serializable {
     return this.parameters;
   }
 
+  public void setParameters(Properties properties) {
+    if (properties == null) {
+      this.parameters = null;
+      return;
+    }
+
+    parameters = properties.stringPropertyNames().stream()
+        .map(k -> new ParameterType(k, 
properties.getProperty(k))).collect(Collectors.toList());
+  }
+
   @Override
   public boolean equals(Object o) {
     if (this == o) {
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 c1b8b21..ca9ac28 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
@@ -2060,7 +2060,7 @@ public class RegionAttributesType implements Serializable 
{
 
     public static EvictionAttributes generate(String evictionAction,
         Integer maxMemory, Integer maxEntryCount,
-        String objectSizer) {
+        ClassName objectSizer) {
       if (evictionAction == null && maxMemory == null && maxEntryCount == null
           && objectSizer == null) {
         return null;
@@ -2074,13 +2074,19 @@ public class RegionAttributesType implements 
Serializable {
         LruHeapPercentage heapPercentage =
             new LruHeapPercentage();
         heapPercentage.setAction(action);
-        heapPercentage.setClassName(objectSizer);
+        if (objectSizer != null) {
+          heapPercentage.setClassName(objectSizer.getClassName());
+          heapPercentage.setParameters(objectSizer.getInitProperties());
+        }
         evictionAttributes.setLruHeapPercentage(heapPercentage);
       } else if (maxMemory != null) {
         LruMemorySize memorySize =
             new LruMemorySize();
         memorySize.setAction(action);
-        memorySize.setClassName(objectSizer);
+        if (objectSizer != null) {
+          memorySize.setClassName(objectSizer.getClassName());
+          memorySize.setParameters(objectSizer.getInitProperties());
+        }
         memorySize.setMaximum(maxMemory.toString());
         evictionAttributes.setLruMemorySize(memorySize);
       } else {
@@ -2093,6 +2099,15 @@ public class RegionAttributesType implements 
Serializable {
       return evictionAttributes;
     }
 
+    public static EvictionAttributes generate(String evictionAction,
+        Integer maxMemory, Integer maxEntryCount,
+        String objectSizer) {
+      if (objectSizer == null) {
+        return generate(evictionAction, maxMemory, maxEntryCount, (ClassName) 
null);
+      }
+      return generate(evictionAction, maxMemory, maxEntryCount, new 
ClassName(objectSizer));
+    }
+
     /**
      * Gets the value of the lruEntryCount property.
      *
diff --git 
a/geode-core/src/main/java/org/apache/geode/management/internal/configuration/converters/RegionConverter.java
 
b/geode-core/src/main/java/org/apache/geode/management/internal/configuration/converters/RegionConverter.java
index 6baf472..461cdb7 100644
--- 
a/geode-core/src/main/java/org/apache/geode/management/internal/configuration/converters/RegionConverter.java
+++ 
b/geode-core/src/main/java/org/apache/geode/management/internal/configuration/converters/RegionConverter.java
@@ -31,6 +31,8 @@ import org.apache.geode.management.configuration.Region;
 import org.apache.geode.management.configuration.RegionType;
 
 public class RegionConverter extends ConfigurationConverter<Region, 
RegionConfig> {
+  private final ClassNameConverter classNameConverter = new 
ClassNameConverter();
+
   @Override
   protected Region fromNonNullXmlObject(RegionConfig xmlObject) {
     Region region = new Region();
@@ -74,6 +76,20 @@ public class RegionConverter extends 
ConfigurationConverter<Region, RegionConfig
       if (!expirations.isEmpty()) {
         region.setExpirations(expirations);
       }
+
+      if (regionAttributes.getEvictionAttributes() != null) {
+        RegionAttributesType.EvictionAttributes evictionAttributes =
+            regionAttributes.getEvictionAttributes();
+        if (evictionAttributes.getLruMemorySize() != null) {
+          
region.setEviction(convertFrom(evictionAttributes.getLruMemorySize()));
+        }
+        if (evictionAttributes.getLruEntryCount() != null) {
+          
region.setEviction(convertFrom(evictionAttributes.getLruEntryCount()));
+        }
+        if (evictionAttributes.getLruHeapPercentage() != null) {
+          
region.setEviction(convertFrom(evictionAttributes.getLruHeapPercentage()));
+        }
+      }
     }
 
     return region;
@@ -93,7 +109,6 @@ public class RegionConverter extends 
ConfigurationConverter<Region, RegionConfig
     attributesType.setDiskStoreName(configObject.getDiskStoreName());
     attributesType.setKeyConstraint(configObject.getKeyConstraint());
     attributesType.setValueConstraint(configObject.getValueConstraint());
-    region.setRegionAttributes(attributesType);
 
     if (configObject.getRedundantCopies() != null) {
       RegionAttributesType.PartitionAttributes partitionAttributes =
@@ -115,9 +130,72 @@ public class RegionConverter extends 
ConfigurationConverter<Region, RegionConfig
         }
       }
     }
+
+    if (configObject.getEviction() != null) {
+      
attributesType.setEvictionAttributes(convertFrom(configObject.getEviction()));
+    }
+
+    region.setRegionAttributes(attributesType);
     return region;
   }
 
+  private RegionAttributesType.EvictionAttributes convertFrom(Region.Eviction 
eviction) {
+    return 
RegionAttributesType.EvictionAttributes.generate(getEvictionActionString(eviction),
+        eviction.getMemorySizeMb(), eviction.getEntryCount(), 
eviction.getObjectSizer());
+  }
+
+  private String getEvictionActionString(Region.Eviction eviction) {
+    if (eviction.getAction() == null) {
+      return "local-destroy";
+    } else {
+      switch (eviction.getAction()) {
+        case LOCAL_DESTROY:
+          return "local-destroy";
+        case OVERFLOW_TO_DISK:
+          return "overflow-to-disk";
+        default:
+          throw new IllegalStateException("Unhandled eviction action: " + 
eviction.getAction());
+      }
+    }
+  }
+
+  private Region.EvictionAction getEvictionAction(EnumActionDestroyOverflow 
evictionAction) {
+    switch (evictionAction) {
+      case LOCAL_DESTROY:
+        return Region.EvictionAction.LOCAL_DESTROY;
+      case OVERFLOW_TO_DISK:
+        return Region.EvictionAction.OVERFLOW_TO_DISK;
+      default:
+        throw new IllegalStateException("Unhandled eviction action xml: " + 
evictionAction);
+    }
+  }
+
+  Region.Eviction convertFrom(
+      RegionAttributesType.EvictionAttributes.LruMemorySize 
evictionAttributes) {
+    Region.Eviction eviction = new Region.Eviction();
+    eviction.setAction(getEvictionAction(evictionAttributes.getAction()));
+    
eviction.setMemorySizeMb(Integer.parseInt(evictionAttributes.getMaximum()));
+    
eviction.setObjectSizer(classNameConverter.fromXmlObject(evictionAttributes));
+    return eviction;
+  }
+
+  Region.Eviction convertFrom(
+      RegionAttributesType.EvictionAttributes.LruEntryCount 
evictionAttributes) {
+    Region.Eviction eviction = new Region.Eviction();
+    eviction.setAction(getEvictionAction(evictionAttributes.getAction()));
+    eviction.setEntryCount(Integer.parseInt(evictionAttributes.getMaximum()));
+    return eviction;
+  }
+
+  Region.Eviction convertFrom(
+      RegionAttributesType.EvictionAttributes.LruHeapPercentage 
evictionAttributes) {
+    Region.Eviction eviction = new Region.Eviction();
+    eviction.setAction(getEvictionAction(evictionAttributes.getAction()));
+    
eviction.setObjectSizer(classNameConverter.fromXmlObject(evictionAttributes));
+    eviction.setType(Region.EvictionType.HEAP_PERCENTAGE);
+    return eviction;
+  }
+
   RegionAttributesType.ExpirationAttributesType convertFrom(Region.Expiration 
expiration) {
     RegionAttributesType.ExpirationAttributesType xmlExpiration =
         new RegionAttributesType.ExpirationAttributesType();
diff --git 
a/geode-core/src/main/java/org/apache/geode/management/internal/configuration/validators/RegionConfigValidator.java
 
b/geode-core/src/main/java/org/apache/geode/management/internal/configuration/validators/RegionConfigValidator.java
index 80ee5c9..1315d91 100644
--- 
a/geode-core/src/main/java/org/apache/geode/management/internal/configuration/validators/RegionConfigValidator.java
+++ 
b/geode-core/src/main/java/org/apache/geode/management/internal/configuration/validators/RegionConfigValidator.java
@@ -98,6 +98,39 @@ public class RegionConfigValidator implements 
ConfigurationValidator<Region> {
         existingTypes.add(expiration.getType());
       }
     }
+
+    // validate eviction
+    validateEviction(config.getEviction());
+  }
+
+  private void validateEviction(Region.Eviction eviction) {
+    if (eviction == null) {
+      return;
+    }
+
+    Region.EvictionType type = eviction.getType();
+    if (type == null) {
+      throw new IllegalArgumentException("Eviction type must be set.");
+    }
+
+    switch (type) {
+      case ENTRY_COUNT:
+        if (eviction.getEntryCount() == null) {
+          throw new IllegalArgumentException(
+              "EntryCount must be set for: " + type);
+        }
+        if (eviction.getObjectSizer() != null) {
+          throw new IllegalArgumentException(
+              "ObjectSizer must not be set for: " + type);
+        }
+        break;
+      case MEMORY_SIZE:
+        if (eviction.getMemorySizeMb() == null) {
+          throw new IllegalArgumentException(
+              "MemorySizeMb must be set for: " + type);
+        }
+        break;
+    }
   }
 
   private void validate(Region.Expiration expiration) {
diff --git 
a/geode-core/src/main/resources/org/apache/geode/internal/sanctioned-geode-management-serializables.txt
 
b/geode-core/src/main/resources/org/apache/geode/internal/sanctioned-geode-management-serializables.txt
index 2c2b377..80ed3b0 100644
--- 
a/geode-core/src/main/resources/org/apache/geode/internal/sanctioned-geode-management-serializables.txt
+++ 
b/geode-core/src/main/resources/org/apache/geode/internal/sanctioned-geode-management-serializables.txt
@@ -8,7 +8,10 @@ 
org/apache/geode/management/configuration/GroupableConfiguration,false,group:jav
 
org/apache/geode/management/configuration/Index,false,expression:java/lang/String,keyIndex:java/lang/Boolean,name:java/lang/String,regionPath:java/lang/String
 org/apache/geode/management/configuration/Member,false,id:java/lang/String
 
org/apache/geode/management/configuration/Pdx,false,autoSerializer:org/apache/geode/management/configuration/AutoSerializer,diskStoreName:java/lang/String,ignoreUnreadFields:java/lang/Boolean,pdxSerializer:org/apache/geode/management/configuration/ClassName,readSerialized:java/lang/Boolean
-org/apache/geode/management/configuration/Region,false,diskStoreName:java/lang/String,expirations:java/util/List,keyConstraint:java/lang/String,name:java/lang/String,redundantCopies:java/lang/Integer,type:org/apache/geode/management/configuration/RegionType,valueConstraint:java/lang/String
+org/apache/geode/management/configuration/Region,false,diskStoreName:java/lang/String,eviction:org/apache/geode/management/configuration/Region$Eviction,expirations:java/util/List,keyConstraint:java/lang/String,name:java/lang/String,redundantCopies:java/lang/Integer,type:org/apache/geode/management/configuration/RegionType,valueConstraint:java/lang/String
+org/apache/geode/management/configuration/Region$Eviction,false,action:org/apache/geode/management/configuration/Region$EvictionAction,limit:java/lang/Integer,objectSizer:org/apache/geode/management/configuration/ClassName,type:org/apache/geode/management/configuration/Region$EvictionType
+org/apache/geode/management/configuration/Region$EvictionAction,false
+org/apache/geode/management/configuration/Region$EvictionType,false
 
org/apache/geode/management/configuration/Region$Expiration,false,action:org/apache/geode/management/configuration/Region$ExpirationAction,timeInSeconds:java/lang/Integer,type:org/apache/geode/management/configuration/Region$ExpirationType
 org/apache/geode/management/configuration/Region$ExpirationAction,false
 org/apache/geode/management/configuration/Region$ExpirationType,false
@@ -16,6 +19,6 @@ org/apache/geode/management/configuration/RegionType,false
 
org/apache/geode/management/runtime/CacheServerInfo,true,1,bindAddress:java/lang/String,isRunning:boolean,maxConnections:int,maxThreads:int,port:int
 
org/apache/geode/management/runtime/GatewayReceiverInfo,false,bindAddress:java/lang/String,connectedSenders:java/lang/String[],hostnameForSenders:java/lang/String,port:int,running:boolean,senderCount:int
 
org/apache/geode/management/runtime/MemberInformation,true,1,cacheServerList:java/util/List,cacheXmlFilePath:java/lang/String,clientCount:int,cpuUsage:double,groups:java/lang/String,heapUsage:long,host:java/lang/String,hostedRegions:java/util/Set,httpServiceBindAddress:java/lang/String,httpServicePort:int,id:java/lang/String,initHeapSize:long,isCoordinator:boolean,isSecured:boolean,isServer:boolean,locatorPort:int,locators:java/lang/String,logFilePath:java/lang/String,maxHeapSize:long,of
 [...]
- 
org/apache/geode/management/runtime/PdxInfo,false,diskStoreName:java/lang/String,ignoreUnreadFields:boolean,pdxSerializer:java/lang/String,readSerialized:boolean
+org/apache/geode/management/runtime/PdxInfo,false,diskStoreName:java/lang/String,ignoreUnreadFields:boolean,pdxSerializer:java/lang/String,readSerialized:boolean
 
org/apache/geode/management/runtime/RuntimeInfo,false,memberName:java/lang/String
 org/apache/geode/management/runtime/RuntimeRegionInfo,false,entryCount:long
diff --git 
a/geode-core/src/test/java/org/apache/geode/cache/configuration/RegionAttributesTypeTest.java
 
b/geode-core/src/test/java/org/apache/geode/cache/configuration/RegionAttributesTypeTest.java
index 4a3a11e..52ba030 100644
--- 
a/geode-core/src/test/java/org/apache/geode/cache/configuration/RegionAttributesTypeTest.java
+++ 
b/geode-core/src/test/java/org/apache/geode/cache/configuration/RegionAttributesTypeTest.java
@@ -108,19 +108,20 @@ public class RegionAttributesTypeTest {
 
   @Test
   public void generateEvictionAttributes() {
-    EvictionAttributes evictionAttributes = EvictionAttributes.generate(null, 
null, null, null);
+    EvictionAttributes evictionAttributes =
+        EvictionAttributes.generate(null, null, null, (String) null);
     assertThat(evictionAttributes).isNull();
 
-    assertThatThrownBy(() -> EvictionAttributes.generate(null, 8, null, null))
+    assertThatThrownBy(() -> EvictionAttributes.generate(null, 8, null, 
(String) null))
         .isInstanceOf(IllegalArgumentException.class);
 
-    evictionAttributes = EvictionAttributes.generate("local-destroy", null, 
null, null);
+    evictionAttributes = EvictionAttributes.generate("local-destroy", null, 
null, (String) null);
     assertThat(evictionAttributes.getLruHeapPercentage().getAction().value())
         .isEqualTo("local-destroy");
     assertThat(evictionAttributes.getLruMemorySize()).isNull();
     assertThat(evictionAttributes.getLruEntryCount()).isNull();
 
-    evictionAttributes = EvictionAttributes.generate("local-destroy", 10, 
null, null);
+    evictionAttributes = EvictionAttributes.generate("local-destroy", 10, 
null, (String) null);
     assertThat(evictionAttributes.getLruHeapPercentage()).isNull();
     
assertThat(evictionAttributes.getLruMemorySize().getMaximum()).isEqualTo("10");
     assertThat(evictionAttributes.getLruMemorySize().getAction().value())
@@ -128,14 +129,14 @@ public class RegionAttributesTypeTest {
     assertThat(evictionAttributes.getLruEntryCount()).isNull();
 
     // maxEntryCount is ignored when maxMemory is specified
-    evictionAttributes = EvictionAttributes.generate("local-destroy", 10, 20, 
null);
+    evictionAttributes = EvictionAttributes.generate("local-destroy", 10, 20, 
(String) null);
     assertThat(evictionAttributes.getLruHeapPercentage()).isNull();
     
assertThat(evictionAttributes.getLruMemorySize().getMaximum()).isEqualTo("10");
     assertThat(evictionAttributes.getLruMemorySize().getAction().value())
         .isEqualTo("local-destroy");
     assertThat(evictionAttributes.getLruEntryCount()).isNull();
 
-    evictionAttributes = EvictionAttributes.generate("local-destroy", null, 
20, null);
+    evictionAttributes = EvictionAttributes.generate("local-destroy", null, 
20, (String) null);
     assertThat(evictionAttributes.getLruHeapPercentage()).isNull();
     assertThat(evictionAttributes.getLruMemorySize()).isNull();
     
assertThat(evictionAttributes.getLruEntryCount().getMaximum()).isEqualTo("20");
diff --git 
a/geode-core/src/test/java/org/apache/geode/management/internal/configuration/converters/RegionConverterTest.java
 
b/geode-core/src/test/java/org/apache/geode/management/internal/configuration/converters/RegionConverterTest.java
index ea383fe..82788f2 100644
--- 
a/geode-core/src/test/java/org/apache/geode/management/internal/configuration/converters/RegionConverterTest.java
+++ 
b/geode-core/src/test/java/org/apache/geode/management/internal/configuration/converters/RegionConverterTest.java
@@ -22,6 +22,7 @@ import static 
org.assertj.core.api.Assertions.assertThatThrownBy;
 import java.io.File;
 import java.net.URL;
 import java.util.List;
+import java.util.Properties;
 
 import org.apache.commons.io.FileUtils;
 import org.junit.Before;
@@ -29,10 +30,13 @@ import org.junit.Test;
 
 import org.apache.geode.cache.RegionShortcut;
 import org.apache.geode.cache.configuration.CacheConfig;
+import org.apache.geode.cache.configuration.EnumActionDestroyOverflow;
+import org.apache.geode.cache.configuration.ParameterType;
 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.internal.config.JAXBService;
+import org.apache.geode.management.configuration.ClassName;
 import org.apache.geode.management.configuration.Region;
 import org.apache.geode.management.configuration.RegionType;
 
@@ -49,7 +53,7 @@ public class RegionConverterTest {
   }
 
   @Test
-  public void fromXmlWithNameType() throws Exception {
+  public void fromXmlWithNameType() {
     config.setName("test");
     
config.setRegionAttributes(converter.createRegionAttributesByType("REPLICATE"));
 
@@ -59,7 +63,7 @@ public class RegionConverterTest {
   }
 
   @Test
-  public void fromXmlWithAll() throws Exception {
+  public void fromXmlWithAll() {
     config.setName("test");
     
config.setRegionAttributes(converter.createRegionAttributesByType("PARTITION"));
 
@@ -85,21 +89,21 @@ public class RegionConverterTest {
   }
 
   @Test
-  public void fromXmlWithLocalType() throws Exception {
+  public void fromXmlWithLocalType() {
     config.setName("test");
     
config.setRegionAttributes(converter.createRegionAttributesByType("LOCAL"));
     
assertThat(converter.fromXmlObject(config).getType()).isEqualTo(RegionType.LEGACY);
   }
 
   @Test
-  public void fromXmlWithNullType() throws Exception {
+  public void fromXmlWithNullType() {
     config.setName("test");
     config.setType((String) null);
     
assertThat(converter.fromXmlObject(config).getType()).isEqualTo(RegionType.LEGACY);
   }
 
   @Test
-  public void fromConfig() throws Exception {
+  public void fromConfig() {
     region.setName("test");
     region.setType(RegionType.PARTITION);
     region.setValueConstraint("foo");
@@ -139,7 +143,7 @@ public class RegionConverterTest {
   }
 
   @Test
-  public void getRegionType() throws Exception {
+  public void getRegionType() {
     assertThat(converter.getRegionType("ABC", null))
         .isEqualTo(RegionType.LEGACY);
 
@@ -190,7 +194,7 @@ public class RegionConverterTest {
   }
 
   @Test
-  public void fromXmlWithPartitionRedundantType() throws Exception {
+  public void fromXmlWithPartitionRedundantType() {
     config.setName("test");
     config.setType("PARTITION_REDUNDANT");
     RegionAttributesType attributesType = new RegionAttributesType();
@@ -203,7 +207,7 @@ public class RegionConverterTest {
   }
 
   @Test
-  public void fromXmlWithPartitionRedundantPersistentType() throws Exception {
+  public void fromXmlWithPartitionRedundantPersistentType() {
     config.setName("test");
     config.setType("PARTITION_REDUNDANT_PERSISTENT");
     RegionAttributesType attributesType = new RegionAttributesType();
@@ -216,7 +220,7 @@ public class RegionConverterTest {
   }
 
   @Test
-  public void fromXmlWithPartitionProxyRedundantType() throws Exception {
+  public void fromXmlWithPartitionProxyRedundantType() {
     config.setName("test");
     config.setType("PARTITION_PROXY_REDUNDANT");
     RegionAttributesType attributesType = new RegionAttributesType();
@@ -230,13 +234,13 @@ public class RegionConverterTest {
   }
 
   @Test
-  public void createRegionAttributesByInvalidType() throws Exception {
+  public void createRegionAttributesByInvalidType() {
     assertThatThrownBy(() -> converter.createRegionAttributesByType("abc"))
         .isInstanceOf(IllegalArgumentException.class);
   }
 
   @Test
-  public void convertRegionExpirationFromXml() throws Exception {
+  public void convertRegionExpirationFromXml() {
     config.setType("REPLICATE");
     config.setName("test");
     RegionAttributesType attributes = new RegionAttributesType();
@@ -269,7 +273,7 @@ public class RegionConverterTest {
   }
 
   @Test
-  public void convertRegionExpirationFromConfig() throws Exception {
+  public void convertRegionExpirationFromConfig() {
     region.setName("test");
     region.setType(RegionType.REPLICATE);
     region.addExpiry(Region.ExpirationType.ENTRY_IDLE_TIME, 100, null);
@@ -287,7 +291,7 @@ public class RegionConverterTest {
   }
 
   @Test
-  public void convertExpirationFromConfig() throws Exception {
+  public void convertExpirationFromConfig() {
     Region.Expiration expiration = new Region.Expiration();
     expiration.setTimeInSeconds(2);
     RegionAttributesType.ExpirationAttributesType expirationAttributes =
@@ -306,7 +310,7 @@ public class RegionConverterTest {
   }
 
   @Test
-  public void convertExpirationFromXml() throws Exception {
+  public void convertExpirationFromXml() {
     RegionAttributesType.ExpirationAttributesType xmlConfig =
         new RegionAttributesType.ExpirationAttributesType();
     Region.Expiration expiration =
@@ -330,4 +334,161 @@ public class RegionConverterTest {
     
assertThat(expiration.getAction()).isEqualTo(Region.ExpirationAction.LEGACY);
     assertThat(expiration.getTimeInSeconds()).isEqualTo(1000);
   }
+
+  @Test
+  public void convertRegionEvictionFromConfigDefaultHeap() {
+    region.setName("test");
+    region.setType(RegionType.REPLICATE);
+    Region.Eviction eviction = new Region.Eviction();
+    region.setEviction(eviction);
+
+    RegionConfig regionConfig = converter.fromConfigObject(region);
+    RegionAttributesType regionAttributes = regionConfig.getRegionAttributes();
+    assertThat(regionAttributes.getEvictionAttributes()).isNotNull();
+    
assertThat(regionAttributes.getEvictionAttributes().getLruHeapPercentage()).isNotNull();
+    
assertThat(regionAttributes.getEvictionAttributes().getLruHeapPercentage().getAction())
+        .isEqualTo(
+            EnumActionDestroyOverflow.LOCAL_DESTROY);
+    
assertThat(regionAttributes.getEvictionAttributes().getLruHeapPercentage().getClassName())
+        .isNull();
+  }
+
+  @Test
+  public void convertRegionEvictionFromConfigMemorySize() {
+    region.setName("test");
+    region.setType(RegionType.REPLICATE);
+    Region.Eviction eviction = new Region.Eviction();
+    eviction.setMemorySizeMb(10);
+    eviction.setAction(Region.EvictionAction.OVERFLOW_TO_DISK);
+    Properties properties = new Properties();
+    properties.setProperty("key", "value");
+    eviction.setObjectSizer(new ClassName("ObjectSizer", properties));
+    region.setEviction(eviction);
+
+    RegionConfig regionConfig = converter.fromConfigObject(region);
+    RegionAttributesType regionAttributes = regionConfig.getRegionAttributes();
+    assertThat(regionAttributes.getEvictionAttributes()).isNotNull();
+    
assertThat(regionAttributes.getEvictionAttributes().getLruMemorySize()).isNotNull();
+    
assertThat(regionAttributes.getEvictionAttributes().getLruMemorySize().getAction()).isEqualTo(
+        EnumActionDestroyOverflow.OVERFLOW_TO_DISK);
+    
assertThat(regionAttributes.getEvictionAttributes().getLruMemorySize().getMaximum())
+        .isEqualTo("10");
+    
assertThat(regionAttributes.getEvictionAttributes().getLruMemorySize().getClassName())
+        .isEqualTo("ObjectSizer");
+    
assertThat(regionAttributes.getEvictionAttributes().getLruMemorySize().getParameters())
+        .containsExactly(new ParameterType("key", "value"));
+
+  }
+
+  @Test
+  public void convertRegionEvictionFromConfigEntryCount() {
+    region.setName("test");
+    region.setType(RegionType.REPLICATE);
+    Region.Eviction eviction = new Region.Eviction();
+    eviction.setEntryCount(10);
+    eviction.setAction(Region.EvictionAction.LOCAL_DESTROY);
+    region.setEviction(eviction);
+
+    RegionConfig regionConfig = converter.fromConfigObject(region);
+    RegionAttributesType regionAttributes = regionConfig.getRegionAttributes();
+    assertThat(regionAttributes.getEvictionAttributes()).isNotNull();
+    
assertThat(regionAttributes.getEvictionAttributes().getLruEntryCount()).isNotNull();
+    
assertThat(regionAttributes.getEvictionAttributes().getLruEntryCount().getAction()).isEqualTo(
+        EnumActionDestroyOverflow.LOCAL_DESTROY);
+    
assertThat(regionAttributes.getEvictionAttributes().getLruEntryCount().getMaximum())
+        .isEqualTo("10");
+  }
+
+  @Test
+  public void convertRegionEvictionFromXMLMemorySize() {
+    config.setType("REPLICATE");
+    config.setName("test");
+    RegionAttributesType attributes = new RegionAttributesType();
+
+    RegionAttributesType.EvictionAttributes.LruMemorySize evictionXmlConfig =
+        new RegionAttributesType.EvictionAttributes.LruMemorySize();
+    evictionXmlConfig.setMaximum("100");
+    evictionXmlConfig.setAction(EnumActionDestroyOverflow.OVERFLOW_TO_DISK);
+    evictionXmlConfig.setClassName("ObjectSizer");
+    Properties properties = new Properties();
+    properties.setProperty("key", "value");
+    evictionXmlConfig.setParameters(properties);
+
+    RegionAttributesType.EvictionAttributes evictionAttributes =
+        new RegionAttributesType.EvictionAttributes();
+    evictionAttributes.setLruMemorySize(evictionXmlConfig);
+    attributes.setEvictionAttributes(evictionAttributes);
+    config.setRegionAttributes(attributes);
+
+    Region region = converter.fromXmlObject(config);
+    Region.Eviction eviction = region.getEviction();
+    assertThat(eviction.getType()).isEqualTo(Region.EvictionType.MEMORY_SIZE);
+    
assertThat(eviction.getAction()).isEqualTo(Region.EvictionAction.OVERFLOW_TO_DISK);
+    assertThat(eviction.getMemorySizeMb()).isEqualTo(100);
+    
assertThat(eviction.getObjectSizer().getClassName()).isEqualTo("ObjectSizer");
+    
assertThat(eviction.getObjectSizer().getInitProperties()).containsEntry("key", 
"value");
+    assertThat(eviction.getEntryCount()).isNull();
+
+    evictionXmlConfig.setAction(EnumActionDestroyOverflow.LOCAL_DESTROY);
+    eviction = converter.convertFrom(evictionXmlConfig);
+    
assertThat(eviction.getAction()).isEqualTo(Region.EvictionAction.LOCAL_DESTROY);
+  }
+
+  @Test
+  public void convertRegionEvicionFromXMLEntrySize() {
+    config.setType("REPLICATE");
+    config.setName("test");
+    RegionAttributesType attributes = new RegionAttributesType();
+
+    RegionAttributesType.EvictionAttributes.LruEntryCount evictionXmlConfig =
+        new RegionAttributesType.EvictionAttributes.LruEntryCount();
+    evictionXmlConfig.setMaximum("100");
+    evictionXmlConfig.setAction(EnumActionDestroyOverflow.OVERFLOW_TO_DISK);
+
+    RegionAttributesType.EvictionAttributes evictionAttributes =
+        new RegionAttributesType.EvictionAttributes();
+    evictionAttributes.setLruEntryCount(evictionXmlConfig);
+    attributes.setEvictionAttributes(evictionAttributes);
+    config.setRegionAttributes(attributes);
+
+    Region region = converter.fromXmlObject(config);
+    Region.Eviction eviction = region.getEviction();
+    assertThat(eviction.getType()).isEqualTo(Region.EvictionType.ENTRY_COUNT);
+    
assertThat(eviction.getAction()).isEqualTo(Region.EvictionAction.OVERFLOW_TO_DISK);
+    assertThat(eviction.getEntryCount()).isEqualTo(100);
+    assertThat(eviction.getMemorySizeMb()).isNull();
+
+    evictionXmlConfig.setAction(EnumActionDestroyOverflow.LOCAL_DESTROY);
+    eviction = converter.convertFrom(evictionXmlConfig);
+    
assertThat(eviction.getAction()).isEqualTo(Region.EvictionAction.LOCAL_DESTROY);
+  }
+
+  @Test
+  public void convertRegionEvictionFromXMLHeapSize() {
+    config.setType("REPLICATE");
+    config.setName("test");
+    RegionAttributesType attributes = new RegionAttributesType();
+
+    RegionAttributesType.EvictionAttributes.LruHeapPercentage 
evictionXmlConfig =
+        new RegionAttributesType.EvictionAttributes.LruHeapPercentage();
+    evictionXmlConfig.setAction(EnumActionDestroyOverflow.OVERFLOW_TO_DISK);
+
+    RegionAttributesType.EvictionAttributes evictionAttributes =
+        new RegionAttributesType.EvictionAttributes();
+    evictionAttributes.setLruHeapPercentage(evictionXmlConfig);
+    attributes.setEvictionAttributes(evictionAttributes);
+    config.setRegionAttributes(attributes);
+
+    Region region = converter.fromXmlObject(config);
+    Region.Eviction eviction = region.getEviction();
+    
assertThat(eviction.getType()).isEqualTo(Region.EvictionType.HEAP_PERCENTAGE);
+    
assertThat(eviction.getAction()).isEqualTo(Region.EvictionAction.OVERFLOW_TO_DISK);
+    assertThat(eviction.getMemorySizeMb()).isNull();
+    assertThat(eviction.getEntryCount()).isNull();
+
+    evictionXmlConfig.setAction(EnumActionDestroyOverflow.LOCAL_DESTROY);
+    eviction = converter.convertFrom(evictionXmlConfig);
+    
assertThat(eviction.getAction()).isEqualTo(Region.EvictionAction.LOCAL_DESTROY);
+  }
+
 }
diff --git 
a/geode-core/src/test/java/org/apache/geode/management/internal/configuration/validators/RegionConfigValidatorTest.java
 
b/geode-core/src/test/java/org/apache/geode/management/internal/configuration/validators/RegionConfigValidatorTest.java
index 3560302..f717d6c 100644
--- 
a/geode-core/src/test/java/org/apache/geode/management/internal/configuration/validators/RegionConfigValidatorTest.java
+++ 
b/geode-core/src/test/java/org/apache/geode/management/internal/configuration/validators/RegionConfigValidatorTest.java
@@ -30,6 +30,7 @@ import org.junit.Test;
 
 import org.apache.geode.internal.cache.InternalCache;
 import org.apache.geode.internal.security.SecurityService;
+import org.apache.geode.management.configuration.ClassName;
 import org.apache.geode.management.configuration.Region;
 import org.apache.geode.management.configuration.RegionType;
 import org.apache.geode.management.internal.CacheElementOperation;
@@ -40,6 +41,7 @@ public class RegionConfigValidatorTest {
   private RegionConfigValidator validator;
   private Region config;
   private SecurityService securityService;
+  private Region.Eviction eviction;
 
   @Before
   public void before() throws Exception {
@@ -48,6 +50,7 @@ public class RegionConfigValidatorTest {
     when(cache.getSecurityService()).thenReturn(securityService);
     validator = new RegionConfigValidator(cache);
     config = new Region();
+    eviction = new Region.Eviction();
   }
 
   @Test
@@ -102,7 +105,7 @@ public class RegionConfigValidatorTest {
   }
 
   @Test
-  public void invalidType() throws Exception {
+  public void invalidType() {
     config.setName("test");
     config.setType(RegionType.LEGACY);
     assertThatThrownBy(() -> validator.validate(CacheElementOperation.CREATE, 
config)).isInstanceOf(
@@ -114,7 +117,7 @@ public class RegionConfigValidatorTest {
 
 
   @Test
-  public void invalidRedundancy() throws Exception {
+  public void invalidRedundancy() {
     config.setRedundantCopies(-1);
     config.setType(RegionType.PARTITION);
     assertThatThrownBy(() -> validator.validate(CacheElementOperation.CREATE, 
config)).isInstanceOf(
@@ -132,7 +135,7 @@ public class RegionConfigValidatorTest {
   }
 
   @Test
-  public void replicateWithRedundancy() throws Exception {
+  public void replicateWithRedundancy() {
     config.setName("test");
     config.setType(RegionType.REPLICATE);
     config.setRedundantCopies(2);
@@ -144,7 +147,7 @@ public class RegionConfigValidatorTest {
   }
 
   @Test
-  public void validateExpiration() throws Exception {
+  public void validateExpiration() {
     config.setName("test");
     config.setType(RegionType.REPLICATE);
     config.addExpiry(null, null, null);
@@ -195,4 +198,91 @@ public class RegionConfigValidatorTest {
     config.addExpiry(Region.ExpirationType.ENTRY_TIME_TO_LIVE, 200, null);
     validator.validate(CacheElementOperation.CREATE, config);
   }
+
+  @Test
+  public void evictionEmptyHappy() {
+    config.setName("test");
+    config.setType(RegionType.REPLICATE);
+    config.setEviction(eviction);
+    assertThatThrownBy(() -> validator.validate(CacheElementOperation.CREATE, 
config))
+        .isInstanceOf(IllegalArgumentException.class)
+        .hasMessageContaining("Eviction type must be set.");
+  }
+
+  @Test
+  public void evictionHeapHappy() {
+    config.setName("test");
+    config.setType(RegionType.REPLICATE);
+    eviction.setType(Region.EvictionType.HEAP_PERCENTAGE);
+    config.setEviction(eviction);
+    validator.validate(CacheElementOperation.CREATE, config);
+  }
+
+  @Test
+  public void evictionEntryCountHappy() {
+    config.setName("test");
+    config.setType(RegionType.REPLICATE);
+    config.setEviction(eviction);
+    eviction.setEntryCount(10);
+    validator.validate(CacheElementOperation.CREATE, config);
+  }
+
+  @Test
+  public void evictionEntryCountMissingCount() {
+    config.setName("test");
+    config.setType(RegionType.REPLICATE);
+    config.setEviction(eviction);
+    eviction.setEntryCount(null);
+    assertThatThrownBy(() -> validator.validate(CacheElementOperation.CREATE, 
config))
+        .isInstanceOf(IllegalArgumentException.class)
+        .hasMessage("EntryCount must be set for: ENTRY_COUNT");
+  }
+
+  @Test
+  public void evictionMaxMemoryMbHappy() {
+    config.setName("test");
+    config.setType(RegionType.REPLICATE);
+    config.setEviction(eviction);
+    eviction.setMemorySizeMb(10);
+    validator.validate(CacheElementOperation.CREATE, config);
+  }
+
+  @Test
+  public void evictionMaxMemoryMbMissingMemorySize() {
+    config.setName("test");
+    config.setType(RegionType.REPLICATE);
+    config.setEviction(eviction);
+    eviction.setMemorySizeMb(null);
+    assertThatThrownBy(() -> validator.validate(CacheElementOperation.CREATE, 
config))
+        .isInstanceOf(IllegalArgumentException.class)
+        .hasMessage("MemorySizeMb must be set for: MEMORY_SIZE");
+  }
+
+  @Test
+  public void objectSizerProvidedHappy() {
+    config.setName("test");
+    config.setType(RegionType.REPLICATE);
+    eviction.setObjectSizer(new ClassName("ObjectSizer"));
+    eviction.setMemorySizeMb(10);
+    config.setEviction(eviction);
+    validator.validate(CacheElementOperation.CREATE, config);
+
+    eviction = new Region.Eviction();
+    config.setEviction(eviction);
+    eviction.setObjectSizer(new ClassName("ObjectSizer"));
+    eviction.setType(Region.EvictionType.HEAP_PERCENTAGE);
+    validator.validate(CacheElementOperation.CREATE, config);
+  }
+
+  @Test
+  public void objectSizerProvidedSad() {
+    config.setName("test");
+    config.setType(RegionType.REPLICATE);
+    config.setEviction(eviction);
+    eviction.setEntryCount(10);
+    eviction.setObjectSizer(new ClassName("ObjectSizer"));
+    assertThatThrownBy(() -> validator.validate(CacheElementOperation.CREATE, 
config))
+        .isInstanceOf(IllegalArgumentException.class)
+        .hasMessage("ObjectSizer must not be set for: ENTRY_COUNT");
+  }
 }
diff --git 
a/geode-management/src/main/java/org/apache/geode/management/configuration/Region.java
 
b/geode-management/src/main/java/org/apache/geode/management/configuration/Region.java
index 9a1266e..8dae55e 100644
--- 
a/geode-management/src/main/java/org/apache/geode/management/configuration/Region.java
+++ 
b/geode-management/src/main/java/org/apache/geode/management/configuration/Region.java
@@ -43,6 +43,8 @@ public class Region extends 
GroupableConfiguration<RuntimeRegionInfo> {
   private Integer redundantCopies;
 
   private List<Expiration> expirations;
+  private Eviction eviction;
+
 
   public Region() {}
 
@@ -144,6 +146,14 @@ public class Region extends 
GroupableConfiguration<RuntimeRegionInfo> {
     this.expirations = 
expirations.stream().filter(Objects::nonNull).collect(Collectors.toList());
   }
 
+  public Eviction getEviction() {
+    return eviction;
+  }
+
+  public void setEviction(Eviction eviction) {
+    this.eviction = eviction;
+  }
+
   public void addExpiry(ExpirationType type, Integer timeout, ExpirationAction 
action) {
     if (expirations == null) {
       expirations = new ArrayList<>();
@@ -173,12 +183,13 @@ public class Region extends 
GroupableConfiguration<RuntimeRegionInfo> {
     LEGACY
   }
 
+
   public static class Expiration implements Serializable {
     private ExpirationType type;
     private Integer timeInSeconds;
     private ExpirationAction action;
 
-    public Expiration() {};
+    public Expiration() {}
 
     public Expiration(ExpirationType type, Integer timeInSeconds, 
ExpirationAction action) {
       setType(type);
@@ -213,4 +224,105 @@ public class Region extends 
GroupableConfiguration<RuntimeRegionInfo> {
       this.action = action;
     }
   }
+
+  public enum EvictionType {
+    ENTRY_COUNT,
+    MEMORY_SIZE,
+    HEAP_PERCENTAGE
+  }
+
+  public enum EvictionAction {
+    LOCAL_DESTROY,
+    OVERFLOW_TO_DISK
+  }
+
+  public static class Eviction implements Serializable {
+    private EvictionType type;
+    private EvictionAction action;
+    private Integer limit;
+    private ClassName objectSizer;
+
+    public Eviction() {}
+
+    public EvictionType getType() {
+      return type;
+    }
+
+    /**
+     * once a type is set, it can not be changed to another value.
+     *
+     * @param type eviction type
+     * @throws IllegalArgumentException if type is already set to another 
value. this is to
+     *         prevent users from trying to send in conflicting attributes in 
json
+     *         format such as {entryCount:10,type:HEAP_PERCENTAGE}
+     */
+    public void setType(EvictionType type) {
+      if (this.type != null && this.type != type) {
+        throw new IllegalArgumentException("Type conflict. Type is already set 
to " + this.type);
+      }
+      this.type = type;
+    }
+
+    public EvictionAction getAction() {
+      return action;
+    }
+
+    public void setAction(EvictionAction action) {
+      this.action = action;
+    }
+
+    public Integer getEntryCount() {
+      if (type == EvictionType.ENTRY_COUNT) {
+        return limit;
+      }
+      return null;
+    }
+
+    /**
+     * this sets the entry count and the eviction type to ENTRY_COUNT
+     *
+     * @param entryCount the entry count
+     * @throws IllegalArgumentException if type is already set to another 
value. This is to prevent
+     *         users from trying to send conflicting json attributes
+     *         such as {type:HEAP_PERCENTAGE,entryCount:10}
+     */
+    public void setEntryCount(Integer entryCount) {
+      if (type != null && type != EvictionType.ENTRY_COUNT) {
+        throw new IllegalArgumentException("Type conflict. Type is already set 
to " + type);
+      }
+      type = EvictionType.ENTRY_COUNT;
+      this.limit = entryCount;
+    }
+
+    public Integer getMemorySizeMb() {
+      if (type == EvictionType.MEMORY_SIZE) {
+        return limit;
+      }
+      return null;
+    }
+
+    /**
+     * this sets the memory size in megabytes and the eviction type to 
MEMORY_SIZE
+     *
+     * @param memorySizeMb the memory size in megabytes
+     * @throws IllegalArgumentException if type is already set to other 
values. This is to prevent
+     *         users from trying to send conflicting json attributes
+     *         such as {type:HEAP_PERCENTAGE,memorySizeMb:100}
+     */
+    public void setMemorySizeMb(Integer memorySizeMb) {
+      if (type != null && type != EvictionType.MEMORY_SIZE) {
+        throw new IllegalArgumentException("Type conflict. type is already set 
to " + type);
+      }
+      type = EvictionType.MEMORY_SIZE;
+      this.limit = memorySizeMb;
+    }
+
+    public ClassName getObjectSizer() {
+      return objectSizer;
+    }
+
+    public void setObjectSizer(ClassName objectSizer) {
+      this.objectSizer = objectSizer;
+    }
+  }
 }
diff --git 
a/geode-management/src/main/java/org/apache/geode/management/internal/PlainClusterManagementServiceBuilder.java
 
b/geode-management/src/main/java/org/apache/geode/management/internal/PlainClusterManagementServiceBuilder.java
index 79df3fc..7702ce4 100644
--- 
a/geode-management/src/main/java/org/apache/geode/management/internal/PlainClusterManagementServiceBuilder.java
+++ 
b/geode-management/src/main/java/org/apache/geode/management/internal/PlainClusterManagementServiceBuilder.java
@@ -30,12 +30,14 @@ import org.apache.http.impl.client.HttpClientBuilder;
 import org.apache.http.message.BasicHeader;
 import org.springframework.http.HttpHeaders;
 import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
+import 
org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
 import org.springframework.web.client.ResponseErrorHandler;
 import org.springframework.web.client.RestTemplate;
 import org.springframework.web.util.DefaultUriTemplateHandler;
 
 import org.apache.geode.management.api.ClusterManagementService;
 import org.apache.geode.management.client.ClusterManagementServiceBuilder;
+import org.apache.geode.util.internal.GeodeJsonMapper;
 
 public class PlainClusterManagementServiceBuilder implements
     ClusterManagementServiceBuilder.PlainBuilder {
@@ -122,9 +124,19 @@ public class PlainClusterManagementServiceBuilder 
implements
     clientBuilder.setSSLHostnameVerifier(hostnameVerifier);
 
     requestFactory.setHttpClient(clientBuilder.build());
-
     restTemplate.setRequestFactory(requestFactory);
 
+    // configure our own ObjectMapper
+    MappingJackson2HttpMessageConverter messageConverter =
+        new MappingJackson2HttpMessageConverter();
+    messageConverter.setPrettyPrint(false);
+    // the client should use a mapper that would ignore unknown properties in 
case the server
+    // is a newer version than the client
+    
messageConverter.setObjectMapper(GeodeJsonMapper.getMapperIgnoringUnknownProperties());
+    restTemplate.getMessageConverters().removeIf(
+        m -> 
m.getClass().getName().equals(MappingJackson2HttpMessageConverter.class.getName()));
+    restTemplate.getMessageConverters().add(messageConverter);
+
     return new ClientClusterManagementService(restTemplate);
   }
 }
diff --git 
a/geode-management/src/test/java/org/apache/geode/management/configuration/RegionTest.java
 
b/geode-management/src/test/java/org/apache/geode/management/configuration/RegionTest.java
index 0b2f6b8..21117b0 100644
--- 
a/geode-management/src/test/java/org/apache/geode/management/configuration/RegionTest.java
+++ 
b/geode-management/src/test/java/org/apache/geode/management/configuration/RegionTest.java
@@ -30,7 +30,7 @@ public class RegionTest {
   private static ObjectMapper mapper = GeodeJsonMapper.getMapper();
 
   @Before
-  public void before() throws Exception {
+  public void before() {
     regionConfig = new Region();
   }
 
@@ -65,6 +65,100 @@ public class RegionTest {
   }
 
   @Test
+  public void correctJsonWithExpiriations() throws Exception {
+    String expireJson = "{\n"
+        + "  \"name\": \"region1\",\n"
+        + "  \"type\": \"PARTITION\",\n"
+        + "  \"expirations\": [\n"
+        + "    {\n"
+        + "      \"type\": \"ENTRY_IDLE_TIME\",\n"
+        + "      \"timeInSeconds\": 3600,\n"
+        + "      \"action\": \"DESTROY\"\n"
+        + "    }\n"
+        + "  ]\n"
+        + "}\n";
+    regionConfig = mapper.readValue(expireJson, Region.class);
+    assertThat(regionConfig.getName()).isEqualTo("region1");
+    assertThat(regionConfig.getType()).isEqualTo(RegionType.PARTITION);
+    assertThat(regionConfig.getExpirations()).isNotNull();
+    assertThat(regionConfig.getExpirations().size()).isEqualTo(1);
+
+    Region.Expiration expiration = regionConfig.getExpirations().get(0);
+    
assertThat(expiration.getType()).isEqualTo(Region.ExpirationType.ENTRY_IDLE_TIME);
+    assertThat(expiration.getTimeInSeconds()).isEqualTo(3600);
+    
assertThat(expiration.getAction()).isEqualTo(Region.ExpirationAction.DESTROY);
+
+    String json2 = mapper.writeValueAsString(regionConfig);
+    System.out.println(json2);
+    assertThat(json2).contains("\"type\":\"PARTITION\"");
+    assertThat(json2).contains("\"name\":\"region1\"");
+    assertThat(json2).contains("\"type\":\"ENTRY_IDLE_TIME\"");
+    assertThat(json2).contains("\"timeInSeconds\":3600");
+    assertThat(json2).contains("\"action\":\"DESTROY\"");
+
+    mapper.readValue(json2, Region.class);
+  }
+
+  @Test
+  public void correctJsonWithEviction() throws Exception {
+    String evictJson = "{\n"
+        + "  \"name\": \"region1\",\n"
+        + "  \"type\": \"PARTITION\",\n"
+        + "  \"eviction\": {\n"
+        + "    \"entryCount\": 100,\n"
+        + "    \"action\": \"OVERFLOW_TO_DISK\"\n"
+        + "  }\n"
+        + "}\n";
+    regionConfig = mapper.readValue(evictJson, Region.class);
+    assertThat(regionConfig.getName()).isEqualTo("region1");
+    assertThat(regionConfig.getType()).isEqualTo(RegionType.PARTITION);
+    assertThat(regionConfig.getEviction()).isNotNull();
+    
assertThat(regionConfig.getEviction().getType()).isEqualTo(Region.EvictionType.ENTRY_COUNT);
+    assertThat(regionConfig.getEviction().getAction())
+        .isEqualTo(Region.EvictionAction.OVERFLOW_TO_DISK);
+    assertThat(regionConfig.getEviction().getEntryCount()).isEqualTo(100);
+
+    String json2 = mapper.writeValueAsString(regionConfig);
+    System.out.println(json2);
+    assertThat(json2).contains("\"type\":\"PARTITION\"");
+    assertThat(json2).contains("\"name\":\"region1\"");
+    assertThat(json2).contains("\"type\":\"ENTRY_COUNT\"");
+    assertThat(json2).contains("\"entryCount\":100");
+    assertThat(json2).doesNotContain("limit");
+    assertThat(json2).contains("\"action\":\"OVERFLOW_TO_DISK\"");
+    mapper.readValue(json2, Region.class);
+  }
+
+  @Test
+  public void readEviction() throws Exception {
+    String json = "{\"action\":\"OVERFLOW_TO_DISK\",\"entryCount\":100}";
+    Region.Eviction eviction = mapper.readValue(json, Region.Eviction.class);
+    assertThat(eviction.getEntryCount()).isEqualTo(100);
+    
assertThat(eviction.getAction()).isEqualTo(Region.EvictionAction.OVERFLOW_TO_DISK);
+
+    String json2 = 
"{\"action\":\"OVERFLOW_TO_DISK\",\"entryCount\":100,\"memorySizeMb\":200}";
+    assertThatThrownBy(() -> mapper.readValue(json2, Region.Eviction.class))
+        .hasMessageContaining("Type conflict");
+
+    String json3 = "{\"entryCount\":100,\"type\":\"HEAP_PERCENTAGE\"}";
+    assertThatThrownBy(() -> mapper.readValue(json3, Region.Eviction.class))
+        .hasMessageContaining("Type conflict");
+
+    String json4 = "{\"entryCount\":100,\"entryCount\":\"200\"}";
+    eviction = mapper.readValue(json4, Region.Eviction.class);
+    assertThat(eviction.getEntryCount()).isEqualTo(200);
+  }
+
+  @Test
+  public void heapIgnoreLimit() throws Exception {
+    Region.Eviction eviction = new Region.Eviction();
+    eviction.setType(Region.EvictionType.HEAP_PERCENTAGE);
+    
assertThat(eviction.getType()).isEqualTo(Region.EvictionType.HEAP_PERCENTAGE);
+    assertThat(eviction.getEntryCount()).isNull();
+    assertThat(eviction.getMemorySizeMb()).isNull();
+  }
+
+  @Test
   public void getUri() {
     regionConfig.setName("regionA");
     assertThat(regionConfig.getLinks().getList()).isEqualTo("/regions");

Reply via email to