5
5
import static io .quarkus .vertx .deployment .VertxConstants .LOCAL_EVENT_BUS_CODEC ;
6
6
import static io .quarkus .vertx .deployment .VertxConstants .UNI ;
7
7
8
+ import java .lang .reflect .Modifier ;
8
9
import java .util .Arrays ;
9
10
import java .util .Collection ;
10
11
import java .util .HashMap ;
12
+ import java .util .HashSet ;
11
13
import java .util .List ;
12
14
import java .util .Map ;
13
15
import java .util .Set ;
17
19
import org .jboss .jandex .AnnotationInstance ;
18
20
import org .jboss .jandex .AnnotationTarget ;
19
21
import org .jboss .jandex .AnnotationValue ;
22
+ import org .jboss .jandex .ClassInfo ;
20
23
import org .jboss .jandex .DotName ;
21
24
import org .jboss .jandex .IndexView ;
22
25
import org .jboss .jandex .MethodInfo ;
23
26
import org .jboss .jandex .ParameterizedType ;
24
27
import org .jboss .jandex .Type ;
28
+ import org .jboss .jandex .Type .Kind ;
25
29
import org .jboss .logging .Logger ;
26
30
27
31
import io .quarkus .arc .deployment .BeanArchiveIndexBuildItem ;
@@ -46,51 +50,71 @@ public void registerCodecs(
46
50
BeanArchiveIndexBuildItem beanArchiveIndexBuildItem ,
47
51
CombinedIndexBuildItem combinedIndex ,
48
52
BuildProducer <MessageCodecBuildItem > messageCodecs ,
49
- BuildProducer <ReflectiveClassBuildItem > reflectiveClass ) {
53
+ BuildProducer <ReflectiveClassBuildItem > reflectiveClass ,
54
+ BuildProducer <LocalCodecSelectorTypesBuildItem > localCodecSelectorTypes ) {
50
55
51
56
final IndexView index = beanArchiveIndexBuildItem .getIndex ();
52
57
Collection <AnnotationInstance > consumeEventAnnotationInstances = index .getAnnotations (CONSUME_EVENT );
53
58
Map <DotName , DotName > codecByTypes = new HashMap <>();
59
+ Set <DotName > selectorTypes = new HashSet <>();
60
+
54
61
for (AnnotationInstance consumeEventAnnotationInstance : consumeEventAnnotationInstances ) {
55
62
AnnotationTarget typeTarget = consumeEventAnnotationInstance .target ();
56
63
if (typeTarget .kind () != AnnotationTarget .Kind .METHOD ) {
57
- throw new UnsupportedOperationException ("@ConsumeEvent annotation must target a method" );
64
+ throw new IllegalStateException ("@ConsumeEvent annotation must target a method" );
58
65
}
59
-
66
+ AnnotationValue local = consumeEventAnnotationInstance .value ("local" );
67
+ boolean isLocal = local == null || local .asBoolean ();
60
68
MethodInfo method = typeTarget .asMethod ();
61
- Type codecTargetFromReturnType = extractPayloadTypeFromReturn (method );
62
- Type codecTargetFromParameter = extractPayloadTypeFromParameter (method );
63
69
70
+ Type codecTargetFromParameter = extractPayloadTypeFromParameter (method );
64
71
// If the @ConsumeEvent set the codec, use this codec. It applies to the parameter
65
72
AnnotationValue codec = consumeEventAnnotationInstance .value ("codec" );
66
73
if (codec != null && codec .asClass ().kind () == Type .Kind .CLASS ) {
67
74
if (codecTargetFromParameter == null ) {
68
75
throw new IllegalStateException ("Invalid `codec` argument in @ConsumeEvent - no parameter" );
69
76
}
70
77
codecByTypes .put (codecTargetFromParameter .name (), codec .asClass ().asClassType ().name ());
71
- } else if (codecTargetFromParameter != null ) {
72
- // Codec is not set, check if we have a built-in codec
73
- if (!hasBuiltInCodec ( codecTargetFromParameter ) ) {
74
- // Ensure local delivery.
75
- AnnotationValue local = consumeEventAnnotationInstance . value ( " local" );
76
- if ( local != null && ! local . asBoolean ()) {
77
- throw new UnsupportedOperationException (
78
- "The generic message codec can only be used for local delivery,"
79
- + ", implement your own event bus codec for " + codecTargetFromParameter .name ()
80
- . toString ());
81
- } else if (! codecByTypes . containsKey ( codecTargetFromParameter . name ())) {
78
+ } else if (codecTargetFromParameter != null && ! hasBuiltInCodec ( codecTargetFromParameter ) ) {
79
+ // Codec is not set and built-in codecs cannot be used
80
+ if (!isLocal ) {
81
+ throw new IllegalStateException (
82
+ "The Local Message Codec can only be used for local delivery,"
83
+ + " you will need to implement a message codec for " + codecTargetFromParameter . name ()
84
+ . toString ()
85
+ + " and make use of @ConsumeEvent#codec()" );
86
+ } else if (! codecByTypes . containsKey ( codecTargetFromParameter .name ())) {
87
+ if ( isConcreteClass ( codecTargetFromParameter , index )) {
88
+ // The default codec makes only sense for concrete classes
82
89
LOGGER .debugf ("Local Message Codec registered for type %s" ,
83
90
codecTargetFromParameter );
84
91
codecByTypes .put (codecTargetFromParameter .name (), LOCAL_EVENT_BUS_CODEC );
92
+ } else {
93
+ LOGGER .debugf ("Local Message Codec will be selected for type %s" , codecTargetFromParameter );
94
+ selectorTypes .add (codecTargetFromParameter .name ());
85
95
}
86
96
}
87
97
}
88
98
89
- if (codecTargetFromReturnType != null && !hasBuiltInCodec (codecTargetFromReturnType )
90
- && !codecByTypes .containsKey (codecTargetFromReturnType .name ())) {
91
-
92
- LOGGER .debugf ("Local Message Codec registered for type %s" , codecTargetFromReturnType );
93
- codecByTypes .put (codecTargetFromReturnType .name (), LOCAL_EVENT_BUS_CODEC );
99
+ Type codecTargetFromReturnType = extractPayloadTypeFromReturn (method );
100
+ if (codecTargetFromReturnType != null && !hasBuiltInCodec (codecTargetFromReturnType )) {
101
+ if (!isLocal ) {
102
+ throw new IllegalStateException (
103
+ "The Local Message Codec can only be used for local delivery,"
104
+ + " you will need to modify the method to consume io.vertx.core.eventbus.Message, implement a message codec for "
105
+ + codecTargetFromReturnType .name ()
106
+ .toString ()
107
+ + " and make use of io.vertx.core.eventbus.DeliveryOptions" );
108
+ } else if (!codecByTypes .containsKey (codecTargetFromReturnType .name ())) {
109
+ if (isConcreteClass (codecTargetFromReturnType , index )) {
110
+ // The default codec makes only sense for concrete classes
111
+ LOGGER .debugf ("Local Message Codec registered for type %s" , codecTargetFromReturnType );
112
+ codecByTypes .put (codecTargetFromReturnType .name (), LOCAL_EVENT_BUS_CODEC );
113
+ } else {
114
+ LOGGER .debugf ("Local Message Codec will be selected for type %s" , codecTargetFromReturnType );
115
+ selectorTypes .add (codecTargetFromReturnType .name ());
116
+ }
117
+ }
94
118
}
95
119
}
96
120
@@ -133,6 +157,9 @@ public void accept(String name) {
133
157
reflectiveClass .produce (ReflectiveClassBuildItem .builder (name ).methods ().build ());
134
158
}
135
159
});
160
+
161
+ localCodecSelectorTypes .produce (new LocalCodecSelectorTypesBuildItem (
162
+ selectorTypes .stream ().map (Object ::toString ).collect (Collectors .toSet ())));
136
163
}
137
164
138
165
private static final List <String > BUILT_IN_CODECS = Arrays .asList (
@@ -220,4 +247,14 @@ private static boolean hasBuiltInCodec(Type type) {
220
247
private static boolean isMessageClass (ParameterizedType type ) {
221
248
return VertxConstants .isMessage (type .name ());
222
249
}
250
+
251
+ private static boolean isConcreteClass (Type type , IndexView index ) {
252
+ if (type != null && type .kind () == Kind .CLASS ) {
253
+ ClassInfo clazz = index .getClassByName (type .name ());
254
+ if (clazz != null ) {
255
+ return !clazz .isInterface () && !Modifier .isAbstract (clazz .flags ());
256
+ }
257
+ }
258
+ return false ;
259
+ }
223
260
}
0 commit comments