@@ -83,6 +83,12 @@ class MessageSerializerGenerator {
8383 /** */
8484 private static final String METHOD_JAVADOC = "/** */" ;
8585
86+ /** */
87+ private static final String RETURN_FALSE_STMT = "return false;" ;
88+
89+ /** */
90+ static final String DLFT_ENUM_MAPPER_CLS = "org.apache.ignite.plugin.extensions.communication.mappers.DefaultEnumMapper" ;
91+
8692 /** Collection of lines for {@code writeTo} method. */
8793 private final List <String > write = new ArrayList <>();
8894
@@ -92,6 +98,9 @@ class MessageSerializerGenerator {
9298 /** Collection of message-specific imports. */
9399 private final Set <String > imports = new TreeSet <>();
94100
101+ /** Collection of Serializer class fields containing mappers for message enum fields. */
102+ private final Set <String > fields = new TreeSet <>();
103+
95104 /** */
96105 private final ProcessingEnvironment env ;
97106
@@ -142,6 +151,8 @@ private String generateSerializerCode(String serClsName) throws IOException {
142151 try (Writer writer = new StringWriter ()) {
143152 writeClassHeader (writer , PKG_NAME , serClsName );
144153
154+ writeClassFields (writer );
155+
145156 // Write #writeTo method.
146157 for (String w : write )
147158 writer .write (w + NL );
@@ -238,10 +249,6 @@ private void processField(VariableElement field, int opt) throws Exception {
238249 if (assignableFrom (field .asType (), type (Throwable .class .getName ())))
239250 throw new UnsupportedOperationException ("You should use ErrorMessage for serialization of throwables." );
240251
241- if (enumType (erasedType (field .asType ())))
242- throw new IllegalArgumentException ("Unsupported enum type: " + field .asType () +
243- ". The enum must be wrapped into a Message (see, for example, TransactionIsolationMessage)." );
244-
245252 writeField (field , opt );
246253 readField (field , opt );
247254 }
@@ -396,6 +403,45 @@ else if (assignableFrom(erasedType(type), type(Collection.class.getName()))) {
396403 "MessageCollectionItemType." + messageCollectionItemType (typeArgs .get (0 )));
397404 }
398405
406+ else if (enumType (type )) {
407+ Element element = env .getTypeUtils ().asElement (type );
408+ imports .add (element .toString ());
409+
410+ String enumName = element .getSimpleName ().toString ();
411+ String enumFieldPrefix = typeNameToFieldName (enumName );
412+
413+ String mapperCallStmnt ;
414+
415+ CustomMapper custMapperAnn = field .getAnnotation (CustomMapper .class );
416+
417+ if (custMapperAnn != null ) {
418+ String fullMapperName = custMapperAnn .value ();
419+ if (fullMapperName == null || fullMapperName .isEmpty ())
420+ throw new IllegalArgumentException ("Please specify a not-null not-empty EnumMapper class name" );
421+
422+ imports .add ("org.apache.ignite.plugin.extensions.communication.mappers.EnumMapper" );
423+ imports .add (fullMapperName );
424+
425+ String simpleName = fullMapperName .substring (fullMapperName .lastIndexOf ('.' ) + 1 );
426+
427+ String mapperFieldName = enumFieldPrefix + "Mapper" ;
428+
429+ fields .add ("private final EnumMapper<" + enumName + "> " + mapperFieldName + " = new " + simpleName + "();" );
430+
431+ mapperCallStmnt = mapperFieldName + ".encode" ;
432+ }
433+ else {
434+ imports .add (DLFT_ENUM_MAPPER_CLS );
435+ String enumValuesFieldName = enumFieldPrefix + "Vals" ;
436+
437+ fields .add ("private final " + enumName + "[] " + enumValuesFieldName + " = " + enumName + ".values();" );
438+
439+ mapperCallStmnt = "DefaultEnumMapper.INSTANCE.encode" ;
440+ }
441+
442+ returnFalseIfEnumWriteFailed (write , "writer.writeByte" , mapperCallStmnt , getExpr );
443+ }
444+
399445 else
400446 throw new IllegalArgumentException ("Unsupported declared type: " + type );
401447
@@ -405,6 +451,15 @@ else if (assignableFrom(erasedType(type), type(Collection.class.getName()))) {
405451 throw new IllegalArgumentException ("Unsupported type kind: " + type .getKind ());
406452 }
407453
454+ /**
455+ * Converts type name to camel case field name. Example: {@code "MyType"} -> {@code "myType"}.
456+ */
457+ private String typeNameToFieldName (String typeName ) {
458+ char [] typeNameChars = typeName .toCharArray ();
459+ typeNameChars [0 ] = Character .toLowerCase (typeNameChars [0 ]);
460+ return new String (typeNameChars );
461+ }
462+
408463 /**
409464 * Generate code of writing single field:
410465 * <pre>
@@ -419,7 +474,24 @@ private void returnFalseIfWriteFailed(Collection<String> code, String accessor,
419474
420475 indent ++;
421476
422- code .add (line ("return false;" ));
477+ code .add (line (RETURN_FALSE_STMT ));
478+
479+ indent --;
480+ }
481+
482+ /**
483+ * Generate code of writing single enum field mapped with EnumMapper:
484+ * <pre>
485+ * if (!writer.writeByte(myEnumMapper.encode(msg.myEnum()))
486+ * return false;
487+ * </pre>
488+ */
489+ private void returnFalseIfEnumWriteFailed (Collection <String > code , String writerCall , String mapperCall , String fieldGetterCall ) {
490+ code .add (line ("if (!%s(%s(msg.%s)))" , writerCall , mapperCall , fieldGetterCall ));
491+
492+ indent ++;
493+
494+ code .add (line (RETURN_FALSE_STMT ));
423495
424496 indent --;
425497 }
@@ -538,6 +610,17 @@ else if (assignableFrom(erasedType(type), type(Collection.class.getName()))) {
538610 "MessageCollectionItemType." + messageCollectionItemType (typeArgs .get (0 )));
539611 }
540612
613+ else if (enumType (type )) {
614+ String fieldPrefix = typeNameToFieldName (env .getTypeUtils ().asElement (type ).getSimpleName ().toString ());
615+
616+ boolean hasCustMapperAnn = field .getAnnotation (CustomMapper .class ) != null ;
617+
618+ String mapperCallStmnt = hasCustMapperAnn ? fieldPrefix + "Mapper.decode" : "DefaultEnumMapper.INSTANCE.decode" ;
619+ String enumValsFieldName = hasCustMapperAnn ? null : fieldPrefix + "Vals" ;
620+
621+ returnFalseIfEnumReadFailed (name , mapperCallStmnt , enumValsFieldName );
622+ }
623+
541624 else
542625 throw new IllegalArgumentException ("Unsupported declared type: " + type );
543626
@@ -646,7 +729,36 @@ private void returnFalseIfReadFailed(String var, String mtd, String... args) {
646729
647730 indent ++;
648731
649- read .add (line ("return false;" ));
732+ read .add (line (RETURN_FALSE_STMT ));
733+
734+ indent --;
735+ }
736+
737+ /**
738+ * Generate code of reading single field:
739+ * <pre>
740+ * msg.id(reader.readInt());
741+ *
742+ * if (!reader.isLastRead())
743+ * return false;
744+ * </pre>
745+ *
746+ * @param msgSetterName Variable name.
747+ * @param mapperDecodeCallStmnt Method name.
748+ */
749+ private void returnFalseIfEnumReadFailed (String msgSetterName , String mapperDecodeCallStmnt , String enumValuesFieldName ) {
750+ if (enumValuesFieldName == null )
751+ read .add (line ("msg.%s(%s(reader.readByte()));" , msgSetterName , mapperDecodeCallStmnt ));
752+ else
753+ read .add (line ("msg.%s(%s(%s, reader.readByte()));" , msgSetterName , mapperDecodeCallStmnt , enumValuesFieldName ));
754+
755+ read .add (EMPTY );
756+
757+ read .add (line ("if (!reader.isLastRead())" ));
758+
759+ indent ++;
760+
761+ read .add (line (RETURN_FALSE_STMT ));
650762
651763 indent --;
652764 }
@@ -680,6 +792,24 @@ private String line(String format, Object... args) {
680792 return sb .toString ();
681793 }
682794
795+ /** Write serializer class fields: enum values, custom enum mappers. */
796+ private void writeClassFields (Writer writer ) throws IOException {
797+ if (fields .isEmpty ())
798+ return ;
799+
800+ indent = 1 ;
801+
802+ for (String field : fields ) {
803+ writer .write (line (METHOD_JAVADOC ));
804+ writer .write (NL );
805+ writer .write (line (field ));
806+ writer .write (NL );
807+ }
808+ writer .write (NL );
809+
810+ indent = 0 ;
811+ }
812+
683813 /** Write header of serializer class: license, imports, class declaration. */
684814 private void writeClassHeader (Writer writer , String pkgName , String serClsName ) throws IOException {
685815 try (InputStream in = getClass ().getClassLoader ().getResourceAsStream ("license.txt" );
@@ -701,8 +831,8 @@ private void writeClassHeader(Writer writer, String pkgName, String serClsName)
701831 imports .add ("org.apache.ignite.plugin.extensions.communication.MessageWriter" );
702832 imports .add ("org.apache.ignite.plugin.extensions.communication.MessageReader" );
703833
704- for (String i : imports )
705- writer .write ("import " + i + ";" + NL );
834+ for (String regularImport : imports )
835+ writer .write ("import " + regularImport + ";" + NL );
706836
707837 writer .write (NL );
708838 writer .write (CLS_JAVADOC );
@@ -727,13 +857,9 @@ private boolean assignableFrom(TypeMirror type, TypeMirror superType) {
727857
728858 /** */
729859 private boolean enumType (TypeMirror type ) {
730- if (type .getKind () == TypeKind .DECLARED ) {
731- Element element = env .getTypeUtils ().asElement (type );
860+ Element element = env .getTypeUtils ().asElement (type );
732861
733- return element != null && element .getKind () == ElementKind .ENUM ;
734- }
735-
736- return false ;
862+ return element != null && element .getKind () == ElementKind .ENUM ;
737863 }
738864
739865 /** */
0 commit comments