11package com .github .sylvainlaurent .maven .swaggervalidator .semantic .validator .definition ;
22
3+ import static com .github .sylvainlaurent .maven .swaggervalidator .semantic .VisitableModelFactory .createVisitableModel ;
4+ import static org .apache .commons .lang3 .StringUtils .isEmpty ;
5+
6+ import java .util .ArrayList ;
7+ import java .util .Collection ;
8+ import java .util .List ;
9+ import java .util .Map ;
10+ import java .util .Set ;
11+
12+ import com .github .sylvainlaurent .maven .swaggervalidator .semantic .VisitablePropertyFactory ;
313import com .github .sylvainlaurent .maven .swaggervalidator .semantic .node .VisitableModel ;
14+ import com .github .sylvainlaurent .maven .swaggervalidator .semantic .node .VisitableProperty ;
15+ import com .github .sylvainlaurent .maven .swaggervalidator .semantic .node .model .ArrayModelWrapper ;
416import com .github .sylvainlaurent .maven .swaggervalidator .semantic .node .model .ComposedModelWrapper ;
517import com .github .sylvainlaurent .maven .swaggervalidator .semantic .node .model .ModelImplWrapper ;
618import com .github .sylvainlaurent .maven .swaggervalidator .semantic .node .model .RefModelWrapper ;
19+ import com .github .sylvainlaurent .maven .swaggervalidator .semantic .node .property .ArrayPropertyWrapper ;
20+ import com .github .sylvainlaurent .maven .swaggervalidator .semantic .node .property .ObjectPropertyWrapper ;
721import com .github .sylvainlaurent .maven .swaggervalidator .semantic .validator .error .DefinitionSemanticError ;
22+ import com .github .sylvainlaurent .maven .swaggervalidator .util .Util ;
823import io .swagger .models .Model ;
924import io .swagger .models .RefModel ;
1025import io .swagger .models .properties .Property ;
1126
12- import java .util .ArrayList ;
13- import java .util .Collection ;
14- import java .util .Collections ;
15- import java .util .List ;
16- import java .util .Map ;
17-
18- import static com .github .sylvainlaurent .maven .swaggervalidator .semantic .VisitableModelFactory .createVisitableModel ;
19- import static java .util .Collections .disjoint ;
20-
2127public class InheritanceChainPropertiesValidator extends ModelValidatorTemplate {
2228
2329 @ Override
24- public void validate (ComposedModelWrapper composedModel ) {
25- Collection <String > childProperties = composedModel .getChild () == null || composedModel .getChild ().getProperties () == null ?
26- Collections .<String >emptyList () :
27- composedModel .getChild ().getProperties ().keySet ();
28- List <String > parentProperties = new ParentPropertiesCollector (composedModel ).getParentProperties ();
29-
30- boolean childHasPropertiesAlreadyPresentInParent = !disjoint (childProperties , parentProperties );
31- if (childHasPropertiesAlreadyPresentInParent ) {
30+ public void validate (ModelImplWrapper modelImplWrapper ) {
31+ List <String > objectProperties = new ArrayList <>(modelImplWrapper .getProperties ().keySet ());
32+ List <String > requiredProperties = modelImplWrapper .getRequired ();
33+
34+ validateDiscriminator (modelImplWrapper .getDiscriminator (), requiredProperties , objectProperties );
35+ validateProperties (objectProperties , requiredProperties );
36+
37+ for (VisitableProperty <? extends Property > property : modelImplWrapper .getProperties ().values ()) {
38+ property .accept (this );
39+ }
40+ }
41+
42+ private void validateDiscriminator (String discriminator , List <String > requiredProperties , List <String > properties ) {
43+ if (isEmpty (discriminator )) {
44+ return ;
45+ }
46+
47+ if (!properties .contains (discriminator )) {
48+ validationErrors .add (new DefinitionSemanticError (holder .getCurrentPath (),
49+ "discriminator \" " + discriminator + "\" is not a property defined at this schema" ));
50+ }
51+
52+ if (!requiredProperties .contains (discriminator )) {
53+ validationErrors .add (new DefinitionSemanticError (holder .getCurrentPath (),
54+ "discriminator property \" " + discriminator + "\" is not marked as required" ));
55+ }
56+ }
57+
58+ private void validateProperties (Collection <String > objectProperties , List <String > required ) {
59+ Set <String > duplicates = Util .findDuplicates (objectProperties );
60+ if (!duplicates .isEmpty ()) {
3261 validationErrors .add (new DefinitionSemanticError (
33- holder .getCurrentPath (), "following properties are already defined in ancestors: "
34- + findCommonProperties (childProperties , parentProperties )));
62+ holder .getCurrentPath (), "following properties are already defined in ancestors: " + duplicates ));
3563 }
64+
65+ duplicates = Util .findDuplicates (required );
66+ if (!duplicates .isEmpty ()) {
67+ validationErrors .add (new DefinitionSemanticError (holder .getCurrentPath (),
68+ "required property is defined multiple times: " + duplicates ));
69+ }
70+
71+ if (objectProperties .containsAll (required )) {
72+ return ;
73+ }
74+
75+ List <String > requiredButNotDefinedProperties = new ArrayList <>(required );
76+ requiredButNotDefinedProperties .removeAll (objectProperties );
77+ validationErrors .add (new DefinitionSemanticError (holder .getCurrentPath (),
78+ "required properties are not defined as object properties: "
79+ + requiredButNotDefinedProperties ));
3680 }
3781
38- private List <String > findCommonProperties (Collection <String > propertyNames , Collection <String > parentPropertyNames ) {
39- List <String > commonProperties = new ArrayList <>(propertyNames );
40- commonProperties .retainAll (parentPropertyNames );
41- return commonProperties ;
82+ @ Override
83+ public void validate (ArrayModelWrapper arrayModelWrapper ) {
84+ if (arrayModelWrapper .getModel ().getItems () == null ) {
85+ validationErrors
86+ .add (new DefinitionSemanticError (holder .getCurrentPath (), "'items' must be defined for an array" ));
87+ return ;
88+ }
89+ arrayModelWrapper .getItems ().accept (this );
4290 }
4391
44- final class ParentPropertiesCollector extends ModelValidatorTemplate {
92+ @ Override
93+ public void validate (ComposedModelWrapper composedModelWrapper ) {
94+ InheritanceChainPropertiesValidator .AllPropertiesCollector allPropertiesCollector =
95+ new InheritanceChainPropertiesValidator .AllPropertiesCollector (
96+ composedModelWrapper );
97+ List <String > objectProperties = allPropertiesCollector .getProperties ();
98+ List <String > requiredProperties = allPropertiesCollector .getRequiredProperties ();
99+ validateProperties (objectProperties , requiredProperties );
100+ if (composedModelWrapper .getChild () != null ) {
101+ for (VisitableProperty <? extends Property > property : createVisitableModel (null , composedModelWrapper .getChild ()).getProperties ()
102+ .values ()) {
103+ property .accept (this );
104+ }
105+ }
106+ }
45107
46- private List <String > parentProperties = new ArrayList <>();
108+ @ Override
109+ public void validate (ObjectPropertyWrapper objectProperty ) {
110+ validateProperties (objectProperty .getProperties ().keySet (), objectProperty .getRequiredProperties ());
47111
48- private VisitableModel root ;
112+ for (Map .Entry <String , Property > property : objectProperty .getProperties ().entrySet ()) {
113+ VisitablePropertyFactory .createVisitableProperty (property .getKey (), property .getValue ()).accept (this );
114+ }
115+ }
116+
117+ @ Override
118+ public void validate (ArrayPropertyWrapper arrayProperty ) {
119+ if (arrayProperty .getProperty ().getItems () == null ) {
120+ validationErrors
121+ .add (new DefinitionSemanticError (holder .getCurrentPath (), "'items' must be defined for an array" ));
122+ return ;
123+ }
124+
125+ arrayProperty .getItems ().accept (this );
126+ }
49127
50- ParentPropertiesCollector (VisitableModel root ) {
51- this .root = root ;
128+ final class AllPropertiesCollector extends ModelValidatorTemplate {
129+ private List <String > properties = new ArrayList <>();
130+ private List <String > requiredProperties = new ArrayList <>();
131+
132+ AllPropertiesCollector (VisitableModel root ) {
133+ root .accept (this );
52134 }
53135
54136 @ Override
55137 public void validate (ModelImplWrapper modelImplWrapper ) {
56- parentProperties .addAll (modelImplWrapper .getProperties ().keySet ());
138+ properties .addAll (modelImplWrapper .getProperties ().keySet ());
139+ requiredProperties .addAll (modelImplWrapper .getRequired ());
57140 }
58141
59142 @ Override
60143 public void validate (RefModelWrapper refModelWrapper ) {
61- String ref = refModelWrapper .getSimpleRef ();
62- Model model = InheritanceChainPropertiesValidator .this .context .getDefinitions ().get (ref );
63- if (model != null ) {
64- createVisitableModel (ref , model ).accept (this );
144+ String refName = refModelWrapper .getSimpleRef ();
145+ if (holder .getVisitedItems ().contains (refName )) {
146+ InheritanceChainPropertiesValidator .this .validationErrors
147+ .add (new DefinitionSemanticError (InheritanceChainPropertiesValidator .this .holder .getCurrentPath (),
148+ "cyclic reference '" + refName + "'." ));
149+ } else {
150+ holder .push (refName );
151+ String ref = refModelWrapper .getSimpleRef ();
152+ Model model = InheritanceChainPropertiesValidator .this .context .getDefinitions ().get (ref );
153+ if (model != null ) {
154+ createVisitableModel (ref , model ).accept (this );
155+ }
65156 }
157+
66158 }
67159
68160 @ Override
69161 public void validate (ComposedModelWrapper composedModelWrapper ) {
70- if (composedModelWrapper != root ) {
71- Map <String , Property > childProperties = composedModelWrapper .getChild ()== null || composedModelWrapper .getChild ().getProperties () == null ?
72- Collections .<String , Property >emptyMap () :
73- composedModelWrapper .getChild ().getProperties ();
74- parentProperties .addAll (childProperties .keySet ());
162+ if (composedModelWrapper .getChild () != null ) {
163+ createVisitableModel (null , composedModelWrapper .getChild ()).accept (this );
75164 }
76-
77165 for (RefModel element : composedModelWrapper .getInterfaces ()) {
78166 createVisitableModel (element .getSimpleRef (), element ).accept (this );
79167 }
80168 }
81169
82- List <String > getParentProperties () {
83- if (parentProperties .isEmpty ()) {
84- root .accept (this );
85- }
86- return parentProperties ;
170+ List <String > getProperties () {
171+ return properties ;
172+ }
173+
174+ List <String > getRequiredProperties () {
175+ return requiredProperties ;
87176 }
88177 }
89- }
178+ }
0 commit comments