Repository: netty/netty
Issue: @Sharable should also support @Target(ElementType.TYPE_USE)

### Expected behavior
`@Sharable` should also be usable with anonymous inner types, so that it is no longer necessary to make named classes (top-level or nested) for sharable handlers. Since Java 8, this is possible with the new `ElementType` `TYPE_USE`.
The practical problem here is that either (a) Netty would have to, at some point, *require* Java 8 (don't think that's the case yet), or (b) an additional Java-8-specific `@Sharable` annotation would have to be introduced.

### Actual behavior
`@Sharable` only targets `ElementType` `TYPE` and requires a proper (i.e., named) class.

### Steps to reproduce
Add `@Sharable` annotation to inner class, observe compilation error.

### Minimal yet complete reproducer code (or URL to code)
```
ChannelInboundHandler echoHandler = new @Sharable ChannelInboundHandlerAdapter() {
      @Override
      public void channelRead(ChannelHandlerContext context, Object message) {
           context.write(message);
      }
}
```
### Netty version
4.1.22.Final

### JVM version (e.g. `java -version`)
1.8.0_152

### OS version (e.g. `uname -a`)
Darwin Kernel Version 16.7.0: Wed Oct  4 00:17:00 PDT 2017; root:xnu-3789.71.6~1/RELEASE_X86_64 x86_64 (MacOS 10.12.6)

Issue comments:
Yes, this is the excellent feature. Also, I would like to have ElementType.TYPE_PARAMETER as well.

The main problem that netty currently support Java 6.
This makes perfect sense and we are planing to start work on the next major version of netty very soon which will hopefully be able to fix this.

Stay tuned, I will start a proposal for all of this soon.
@raner / @kiril-me if you are interested you may want to contribute a PR against master which is Java8+ now.
I can work on that.
@kiril-me thanks a lot for all the help!

Pull request review comments:
2019
nit: final
nit: `new @Sharable ChannelHandlerAdapter() { };`
nit: `new ChannelHandlerAdapter() {};`
Is this correct? Child class could be nonsharable, while it extends `@Sharable`.
I think explicit `@Sharable` annotation for sharable classes is a good idea.
@doom369 not sure I understand you correctly.. but `@Sharable` uses `@Inherited` so if the super-class is sharable the child class should be as well. 
@normanmaurer missed that. Anyway, in that case:

```
 * Indicates that an annotation type is automatically inherited.  If
 * an Inherited meta-annotation is present on an annotation type
 * declaration, and the user queries the annotation type on a class
 * declaration, and the class declaration has no annotation for this type,
 * then the class's superclass will automatically be queried for the
 * annotation type.  This process will be repeated until an annotation for this
 * type is found, or the top of the class hierarchy (Object)
 * is reached.  If no superclass has an annotation for this type, then
 * the query will indicate that the class in question has no such annotation.
```

```
    @ChannelHandler.Sharable
    private static class A {
    }
    private static class B extends A {
    }
    @Test
    public void aaa() {
        System.out.println(B.class.isAnnotationPresent(ChannelHandler.Sharable.class));
       //prints true
    }
```
@doom369 agree... so you are saying we do not need the extra "query" ? If so I think you are right... @kiril-me did you check if you really need it ?
@normanmaurer this check is useful only for the case when the class implements interface marked with `@Sharable`. I don't think this is real use case, however, for this at least 1 more additional test case should be added. Not a big deal.
@kiril-me can you do this ?
@normanmaurer There are differences between annotation of the class and inner anonymous class annotation. 

> @Inherited JavaDoc
> Note that this meta-annotation type has no effect if the annotated
> type is used to annotate anything other than a class.  Note also
> that this meta-annotation only causes annotations to be inherited
> from superclasses; annotations on implemented interfaces have no
> effect.

As @doom369 mentioned, isAnnotationPresent(Sharable.class) looking for @Sharable annotation starting from current class till Object.

But this scenario doesn't work for isAnnotationPresent, because @Inherit does not apply directly to the class:
```
ChannelInboundHandler handler = new @Sharable ChannelInboundHandlerAdapter() {
      @Override
      public void channelRead(ChannelHandlerContext context, Object message) {
           context.write(message);
      }
};
```
Tests checking this. If you comment out following code, test will fails:
```
if (!sharable) {       
                AnnotatedType annotatedType = clazz.getAnnotatedSuperclass();
                sharable = annotatedType.isAnnotationPresent(Sharable.class);
 }
```


Thanks for the explanation.

Patch that resolved the issue:
diff --git a/transport/src/main/java/io/netty/channel/ChannelHandler.java b/transport/src/main/java/io/netty/channel/ChannelHandler.java
index aca5901a8b4..1efdca492cf 100644
--- a/transport/src/main/java/io/netty/channel/ChannelHandler.java
+++ b/transport/src/main/java/io/netty/channel/ChannelHandler.java
@@ -210,7 +210,7 @@ public interface ChannelHandler {
      */
     @Inherited
     @Documented
-    @Target(ElementType.TYPE)
+    @Target({ElementType.TYPE, ElementType.TYPE_USE})
     @Retention(RetentionPolicy.RUNTIME)
     @interface Sharable {
         // no value
diff --git a/transport/src/main/java/io/netty/channel/ChannelHandlerAdapter.java b/transport/src/main/java/io/netty/channel/ChannelHandlerAdapter.java
index 722261ed32c..2b35591172c 100644
--- a/transport/src/main/java/io/netty/channel/ChannelHandlerAdapter.java
+++ b/transport/src/main/java/io/netty/channel/ChannelHandlerAdapter.java
@@ -18,6 +18,7 @@
 
 import io.netty.util.internal.InternalThreadLocalMap;
 
+import java.lang.reflect.AnnotatedType;
 import java.util.Map;
 
 /**
@@ -55,6 +56,10 @@ public boolean isSharable() {
         Boolean sharable = cache.get(clazz);
         if (sharable == null) {
             sharable = clazz.isAnnotationPresent(Sharable.class);
+            if (!sharable) {
+                AnnotatedType annotatedType = clazz.getAnnotatedSuperclass();
+                sharable = annotatedType.isAnnotationPresent(Sharable.class);
+            }
             cache.put(clazz, sharable);
         }
         return sharable;


Test patch:
diff --git a/transport/src/test/java/io/netty/channel/ChannelHandlerAdapterTest.java b/transport/src/test/java/io/netty/channel/ChannelHandlerAdapterTest.java
new file mode 100644
index 00000000000..06123dbb56d
--- /dev/null
+++ b/transport/src/test/java/io/netty/channel/ChannelHandlerAdapterTest.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2019 The Netty Project
+ *
+ * The Netty Project 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 io.netty.channel;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+
+import io.netty.channel.ChannelHandler.Sharable;
+
+public class ChannelHandlerAdapterTest {
+
+    @Sharable
+    private static final class SharableChannelHandlerAdapter extends ChannelHandlerAdapter {
+    }
+
+    @Test
+    public void testSharable() {
+        ChannelHandlerAdapter handler = new SharableChannelHandlerAdapter();
+        assertEquals(true, handler.isSharable());
+    }
+
+    @Test
+    public void testInnerClassSharable() {
+        ChannelHandlerAdapter handler = new @Sharable ChannelHandlerAdapter() { };
+        assertEquals(true, handler.isSharable());
+    }
+
+    @Test
+    public void testWithoutSharable() {
+        ChannelHandlerAdapter handler = new ChannelHandlerAdapter() { };
+        assertEquals(false, handler.isSharable());
+    }
+}