1111import java .util .List ;
1212import java .util .Map ;
1313import java .util .Map .Entry ;
14+ import java .util .Optional ;
1415import java .util .function .Predicate ;
1516import java .util .stream .Collectors ;
1617
2324import com .fasterxml .jackson .module .jsonSchema .JsonSchemaGenerator ;
2425
2526import io .asfjava .ui .core .FormDefinitionGeneratorFactory ;
27+ import io .asfjava .ui .core .form .Action ;
28+ import io .asfjava .ui .core .form .ActionsGroup ;
29+ import io .asfjava .ui .core .form .FieldSet ;
2630import io .asfjava .ui .core .form .Index ;
2731import io .asfjava .ui .core .form .Tab ;
2832import io .asfjava .ui .dto .UiForm ;
@@ -38,39 +42,81 @@ public UiForm generate(Class<? extends Serializable> formDto) throws JsonMapping
3842 JsonSchemaGenerator schemaGen = initSchemaGen (mapper );
3943 JsonSchema schema = generateSchema (formDto , schemaGen );
4044
41- Map <Field , JsonNode > nodes = initFieldFormDefinition (mapper , declaredFields );
45+ Map <Field , JsonNode > nodes = initFieldsFormDefinition (mapper , declaredFields );
4246
4347 Map <Field , JsonNode > sortedNodes = reorderFieldsBasedOnIndex (nodes );
4448
45- handlerGroupedFields ();
49+ handlerGroupedFields (mapper , declaredFields , sortedNodes );
4650
47- ObjectNode tabbedFields = handleTabbedFields (mapper , declaredFields , sortedNodes );
51+ Optional <ObjectNode > tabbedFields = Optional
52+ .ofNullable (handleTabbedFields (mapper , declaredFields , sortedNodes ));
4853
4954 ArrayNode formDefinition = mapper .createArrayNode ();
50- formDefinition . add ( tabbedFields );
55+ tabbedFields . ifPresent ( formDefinition :: add );
5156 sortedNodes .entrySet ().stream ().forEach (nodesElement -> formDefinition .add (nodesElement .getValue ()));
5257
58+ handleActionsAnnotation (mapper , formDto , formDefinition );
59+
5360 return new UiForm (schema , formDefinition );
5461 }
5562
56- private Map <Field , JsonNode > reorderFieldsBasedOnIndex (Map <Field , JsonNode > nodes ) {
63+ private void handleActionsAnnotation (ObjectMapper mapper , Class <? extends Serializable > formDto ,
64+ ArrayNode formDefinition ) {
65+ ObjectNode groupedActionsNode = mapper .createObjectNode ();
66+ ObjectNode actionsNode = mapper .createObjectNode ();
5767
58- Comparator <? super Entry <Field , JsonNode >> tabIndexComparator = (entry1 , entry2 ) -> {
68+ buildActions (mapper , formDto , actionsNode , formDefinition );
69+ buildGroupedActions (mapper , formDto , groupedActionsNode , formDefinition );
70+ }
5971
60- Index field1Index = entry1 . getKey (). getAnnotation ( Index . class );
61- Index field2Index = entry2 . getKey (). getAnnotation ( Index . class );
72+ private void buildActions ( ObjectMapper mapper , Class <? extends Serializable > formDto , ObjectNode actionsNode ,
73+ ArrayNode formDefinition ) {
6274
63- return Integer .compare ((field1Index != null ? field1Index .value () : Integer .MAX_VALUE ),
64- field2Index != null ? field2Index .value () : Integer .MAX_VALUE );
65- };
75+ Action [] actionsAnnotations = formDto .getAnnotationsByType (Action .class );
76+ Arrays .stream (actionsAnnotations ).forEach (action -> {
77+ formDefinition .add (buildActionNode (mapper , action ));
78+ });
79+ }
6680
67- return nodes .entrySet ().stream ().sorted (tabIndexComparator ).collect (Collectors .toMap (Map .Entry ::getKey ,
68- Map .Entry ::getValue , (oldValue , newValue ) -> oldValue , LinkedHashMap ::new ));
81+ private void buildGroupedActions (ObjectMapper mapper , Class <? extends Serializable > formDto , ObjectNode actionsNode ,
82+ ArrayNode formDefinition ) {
83+ Optional <ActionsGroup > actionsAnnotation = Optional .ofNullable (formDto .getAnnotation (ActionsGroup .class ));
84+ actionsAnnotation .ifPresent (actions -> {
85+ actionsNode .put ("type" , "actions" );
86+ ArrayNode items = mapper .createArrayNode ();
87+ Arrays .stream (actions .value ()).forEach (action -> {
88+ ObjectNode node = buildActionNode (mapper , action );
89+ items .add (node );
90+ });
91+ actionsNode .set ("items" , items );
92+
93+ formDefinition .add (actionsNode );
94+ });
95+ }
6996
97+ private ObjectNode buildActionNode (ObjectMapper mapper , Action action ) {
98+ ObjectNode node = mapper .createObjectNode ();
99+ node .put ("type" , action .type ());
100+ node .put ("title" , action .title ());
101+ node .put ("onClick" , action .onClick ());
102+ return node ;
70103 }
71104
72- private void handlerGroupedFields () {
73- // TODO Grouping fieldset must handle it
105+ private ObjectNode handlerGroupedFields (ObjectMapper mapper , Field [] declaredFields ,
106+ Map <Field , JsonNode > sortedNodes ) {
107+ Predicate <? super Field > checkFieldSetAnnotation = field -> field .isAnnotationPresent (FieldSet .class );
108+
109+ Map <String , List <JsonNode >> groupedFields = new LinkedHashMap <>();
110+
111+ Arrays .stream (declaredFields ).filter (checkFieldSetAnnotation )
112+ .forEach (field -> groupFieldsByTab (sortedNodes , field , groupedFields ));
113+
114+ ArrayNode groups = mapper .createArrayNode ();
115+
116+ ObjectNode tabsNode = mapper .createObjectNode ();
117+ tabsNode .put ("type" , "fieldset" );
118+ tabsNode .set ("items" , groups );
119+ return tabsNode ;
74120
75121 }
76122
@@ -83,7 +129,6 @@ private ObjectNode handleTabbedFields(ObjectMapper mapper, Field[] declaredField
83129 Comparator <? super Field > fieldIndexComparator = (entry1 , entry2 ) -> {
84130 Index field1Index = entry1 .getAnnotation (Index .class );
85131 Index field2Index = entry2 .getAnnotation (Index .class );
86-
87132 return Integer .compare ((field1Index != null ? field1Index .value () : Integer .MAX_VALUE ),
88133 field2Index != null ? field2Index .value () : Integer .MAX_VALUE );
89134 };
@@ -103,15 +148,17 @@ private ObjectNode handleTabbedFields(ObjectMapper mapper, Field[] declaredField
103148 tabNode .set ("items" , tabItems );
104149 tabs .add (tabNode );
105150 });
106-
107- ObjectNode tabsNode = mapper .createObjectNode ();
108- tabsNode .put ("type" , "tabs" );
109- tabsNode .set ("tabs" , tabs );
110- return tabsNode ;
151+ if (tabs .size () > 0 ) {
152+ ObjectNode tabsNode = mapper .createObjectNode ();
153+ tabsNode .put ("type" , "tabs" );
154+ tabsNode .set ("tabs" , tabs );
155+ return tabsNode ;
156+ }
157+ return null ;
111158
112159 }
113160
114- private Map <Field , JsonNode > initFieldFormDefinition (ObjectMapper mapper , Field [] declaredFields ) {
161+ private Map <Field , JsonNode > initFieldsFormDefinition (ObjectMapper mapper , Field [] declaredFields ) {
115162 Map <Field , JsonNode > nodes = new HashMap <>();
116163
117164 Arrays .stream (declaredFields ).forEach (field -> buildFormDefinition (nodes , mapper , field ));
@@ -154,6 +201,22 @@ private void buildFieldDefinition(Field field, Annotation annotation, ObjectMapp
154201 });
155202 }
156203
204+ private Map <Field , JsonNode > reorderFieldsBasedOnIndex (Map <Field , JsonNode > nodes ) {
205+
206+ Comparator <? super Entry <Field , JsonNode >> tabIndexComparator = (entry1 , entry2 ) -> {
207+
208+ Index field1Index = entry1 .getKey ().getAnnotation (Index .class );
209+ Index field2Index = entry2 .getKey ().getAnnotation (Index .class );
210+
211+ return Integer .compare ((field1Index != null ? field1Index .value () : Integer .MAX_VALUE ),
212+ field2Index != null ? field2Index .value () : Integer .MAX_VALUE );
213+ };
214+
215+ return nodes .entrySet ().stream ().sorted (tabIndexComparator ).collect (Collectors .toMap (Map .Entry ::getKey ,
216+ Map .Entry ::getValue , (oldValue , newValue ) -> oldValue , LinkedHashMap ::new ));
217+
218+ }
219+
157220 public static UiFormSchemaGenerator get () {
158221 if (instance == null ) {
159222 instance = new UiFormSchemaGenerator ();
0 commit comments