Add a default Enum MB provider.

Signed-off-by: jansupol <jan.supol@oracle.com>
diff --git a/core-common/src/main/java/org/glassfish/jersey/message/internal/EnumMessageProvider.java b/core-common/src/main/java/org/glassfish/jersey/message/internal/EnumMessageProvider.java
new file mode 100644
index 0000000..bcf30bd
--- /dev/null
+++ b/core-common/src/main/java/org/glassfish/jersey/message/internal/EnumMessageProvider.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.message.internal;
+
+import javax.inject.Singleton;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.Produces;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+
+/**
+ * Default provider for enum types.
+ * @since 2.34
+ */
+@Singleton
+@Consumes(MediaType.TEXT_PLAIN)
+@Produces(MediaType.TEXT_PLAIN)
+final class EnumMessageProvider extends AbstractMessageReaderWriterProvider<Enum> {
+
+    @Override
+    public boolean isReadable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
+        return type.isEnum();
+    }
+
+    @Override
+    public Enum readFrom(
+            Class<Enum> type,
+            Type genericType,
+            Annotation[] annotations,
+            MediaType mediaType,
+            MultivaluedMap<String, String> httpHeaders,
+            InputStream entityStream) throws IOException, WebApplicationException {
+        final String value = readFromAsString(entityStream, mediaType);
+        return Enum.valueOf(type, value);
+    }
+
+    @Override
+    public boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
+        return type.isEnum();
+    }
+
+    @Override
+    public void writeTo(
+            Enum anEnum, Class<?> type,
+            Type genericType,
+            Annotation[] annotations,
+            MediaType mediaType,
+            MultivaluedMap<String, Object> httpHeaders,
+            OutputStream entityStream) throws IOException, WebApplicationException {
+        writeToAsString(anEnum.name(), entityStream, mediaType);
+    }
+}
\ No newline at end of file
diff --git a/core-common/src/main/java/org/glassfish/jersey/message/internal/MessagingBinders.java b/core-common/src/main/java/org/glassfish/jersey/message/internal/MessagingBinders.java
index 8c5e67d..3df2ae9 100644
--- a/core-common/src/main/java/org/glassfish/jersey/message/internal/MessagingBinders.java
+++ b/core-common/src/main/java/org/glassfish/jersey/message/internal/MessagingBinders.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2020 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2021 Oracle and/or its affiliates. All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v. 2.0, which is available at
@@ -89,6 +89,7 @@
             bindSingletonWorker(ReaderProvider.class);
             // bindSingletonWorker(RenderedImageProvider.class); - enabledProvidersBinder
             bindSingletonWorker(StringMessageProvider.class);
+            bindSingletonWorker(EnumMessageProvider.class);
 
             // Message body readers -- enabledProvidersBinder
             // bind(SourceProvider.StreamSourceReader.class).to(MessageBodyReader.class).in(Singleton.class);
diff --git a/tests/e2e-entity/src/test/java/org/glassfish/jersey/tests/e2e/entity/EnumEntityTest.java b/tests/e2e-entity/src/test/java/org/glassfish/jersey/tests/e2e/entity/EnumEntityTest.java
new file mode 100644
index 0000000..6e842ff
--- /dev/null
+++ b/tests/e2e-entity/src/test/java/org/glassfish/jersey/tests/e2e/entity/EnumEntityTest.java
@@ -0,0 +1,175 @@
+/*
+ * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.tests.e2e.entity;
+
+import org.glassfish.jersey.server.ResourceConfig;
+import org.glassfish.jersey.test.JerseyTest;
+import org.glassfish.jersey.test.util.runner.ConcurrentRunner;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.client.Entity;
+import javax.ws.rs.core.Application;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+@RunWith(ConcurrentRunner.class)
+public class EnumEntityTest extends JerseyTest {
+
+    public enum SimpleEnum {
+        VALUE1,
+        VALUE2
+    }
+
+    public enum ValueEnum {
+        VALUE100(100),
+        VALUE200(200);
+
+        private final int value;
+
+        ValueEnum(int value) {
+            this.value = value;
+        }
+    }
+
+    @Path("/")
+    public static class EnumResource {
+        @POST
+        @Path("/simple")
+        public String postSimple(SimpleEnum simpleEnum) {
+            return simpleEnum.name();
+        }
+
+        @POST
+        @Path("/value")
+        public String postValue(ValueEnum valueEnum) {
+            return valueEnum.name();
+        }
+
+        @POST
+        @Path("/echo")
+        public String echo(String value) {
+            return value;
+        }
+
+        @PUT
+        @Path("/simple")
+        public SimpleEnum putSimple(String simple) {
+            return SimpleEnum.valueOf(simple);
+        }
+
+        @PUT
+        @Path("value")
+        public ValueEnum putValue(String value) {
+            return ValueEnum.valueOf(value);
+        }
+    }
+
+    @Override
+    protected Application configure() {
+        return new ResourceConfig(EnumResource.class);
+    }
+
+    // Server side tests
+
+    @Test
+    public void testSimpleEnumServerReader() {
+        for (SimpleEnum value : SimpleEnum.values()) {
+            try (Response r = target("simple").request(MediaType.TEXT_PLAIN_TYPE)
+                    .post(Entity.entity(value.name(), MediaType.TEXT_PLAIN_TYPE))) {
+                Assert.assertEquals(value.name(), r.readEntity(String.class));
+            }
+        }
+    }
+
+    @Test
+    public void testValueEnumServerReader() {
+        for (ValueEnum value : ValueEnum.values()) {
+            try (Response r = target("value").request(MediaType.TEXT_PLAIN_TYPE)
+                    .post(Entity.entity(value.name(), MediaType.TEXT_PLAIN_TYPE))) {
+                Assert.assertEquals(value.name(), r.readEntity(String.class));
+            }
+        }
+    }
+
+    @Test
+    public void testSimpleEnumServerWriter() {
+        for (SimpleEnum value : SimpleEnum.values()) {
+            try (Response r = target("simple").request(MediaType.TEXT_PLAIN_TYPE)
+                    .put(Entity.entity(value.name(), MediaType.TEXT_PLAIN_TYPE))) {
+                Assert.assertEquals(value.name(), r.readEntity(String.class));
+            }
+        }
+    }
+
+    @Test
+    public void testValueEnumServerWriter() {
+        for (ValueEnum value : ValueEnum.values()) {
+            try (Response r = target("value").request(MediaType.TEXT_PLAIN_TYPE)
+                    .put(Entity.entity(value.name(), MediaType.TEXT_PLAIN_TYPE))) {
+                Assert.assertEquals(value.name(), r.readEntity(String.class));
+            }
+        }
+    }
+
+    // Client side tests
+
+    @Test
+    public void testSimpleEnumClientReader() {
+        for (SimpleEnum value : SimpleEnum.values()) {
+            try (Response r = target("simple").request(MediaType.TEXT_PLAIN_TYPE)
+                    .post(Entity.entity(value.name(), MediaType.TEXT_PLAIN_TYPE))) {
+                Assert.assertEquals(value, r.readEntity(SimpleEnum.class));
+            }
+        }
+    }
+
+    @Test
+    public void testValueEnumClientReader() {
+        for (ValueEnum value : ValueEnum.values()) {
+            try (Response r = target("value").request(MediaType.TEXT_PLAIN_TYPE)
+                    .post(Entity.entity(value.name(), MediaType.TEXT_PLAIN_TYPE))) {
+                Assert.assertEquals(value, r.readEntity(ValueEnum.class));
+            }
+        }
+    }
+
+    @Test
+    public void testSimpleEnumClientWriter() {
+        for (SimpleEnum value : SimpleEnum.values()) {
+            try (Response r = target("echo").request(MediaType.TEXT_PLAIN_TYPE)
+                    .post(Entity.entity(value, MediaType.TEXT_PLAIN_TYPE))) {
+                Assert.assertEquals(value.name(), r.readEntity(String.class));
+            }
+        }
+    }
+
+    @Test
+    public void testValueEnumClientWriter() {
+        for (ValueEnum value : ValueEnum.values()) {
+            try (Response r = target("echo").request(MediaType.TEXT_PLAIN_TYPE)
+                    .post(Entity.entity(value, MediaType.TEXT_PLAIN_TYPE))) {
+                Assert.assertEquals(value.name(), r.readEntity(String.class));
+            }
+        }
+    }
+
+}