1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.forgerock.api.models;
18
19 import static org.forgerock.api.util.ValidationUtil.isEmpty;
20
21 import java.util.Comparator;
22 import java.util.Objects;
23
24 import org.forgerock.api.ApiValidationException;
25 import org.wrensecurity.guava.common.base.Strings;
26 import org.forgerock.util.i18n.LocalizableString;
27
28 import com.fasterxml.jackson.annotation.JsonInclude;
29 import com.fasterxml.jackson.annotation.JsonProperty;
30 import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
31
32
33
34
35 @JsonInclude(JsonInclude.Include.NON_NULL)
36 @JsonDeserialize(builder = ApiError.Builder.class)
37 public final class ApiError {
38
39
40
41
42 public static final ErrorComparator ERROR_COMPARATOR = new ErrorComparator();
43
44
45 private final Integer code;
46 private final LocalizableString description;
47 private final Schema schema;
48 @JsonProperty("$ref")
49 private final Reference reference;
50
51 private ApiError(Builder builder) {
52 this.code = builder.code;
53 this.description = builder.description;
54 this.schema = builder.schema;
55 this.reference = builder.reference;
56
57 if (reference == null && (code == null || description == null || isEmpty(description.toString()))) {
58 throw new ApiValidationException("code and description are required");
59 }
60 if (reference != null && (code != null || description != null || schema != null)) {
61 throw new ApiValidationException("Cannot set code, description or schema when using a reference");
62 }
63 }
64
65
66
67
68
69
70 public Integer getCode() {
71 return code;
72 }
73
74
75
76
77
78
79 public LocalizableString getDescription() {
80 return description;
81 }
82
83
84
85
86
87
88 public Schema getSchema() {
89 return schema;
90 }
91
92
93
94
95
96
97 public Reference getReference() {
98 return reference;
99 }
100
101 @Override
102 public boolean equals(Object o) {
103 if (this == o) {
104 return true;
105 }
106 if (o == null || getClass() != o.getClass()) {
107 return false;
108 }
109 ApiError apiError = (ApiError) o;
110 return Objects.equals(code, apiError.code)
111 && Objects.equals(description, apiError.description)
112 && Objects.equals(schema, apiError.schema)
113 && Objects.equals(reference, apiError.reference);
114 }
115
116 @Override
117 public int hashCode() {
118 return Objects.hash(code, description, schema, reference);
119 }
120
121
122
123
124
125
126 public static Builder apiError() {
127 return new Builder();
128 }
129
130
131
132
133
134
135
136
137
138
139
140 public static ApiError fromAnnotation(org.forgerock.api.annotations.ApiError apiError,
141 ApiDescription descriptor, Class<?> relativeType) {
142 ApiError apiErrorDefinition = apiError()
143 .description(new LocalizableString(apiError.description(), relativeType))
144 .code(apiError.code())
145 .schema(Schema.fromAnnotation(apiError.detailSchema(), descriptor, relativeType))
146 .build();
147 if (!Strings.isNullOrEmpty(apiError.id())) {
148
149 descriptor.addError(apiError.id(), apiErrorDefinition);
150 return apiError().reference(Reference.reference().value("#/errors/" + apiError.id()).build()).build();
151 } else {
152 return apiErrorDefinition;
153 }
154 }
155
156
157
158
159 public static final class Builder {
160
161
162 private Integer code;
163 private LocalizableString description;
164 private Schema schema;
165 private Reference reference;
166
167 private Builder() {
168 }
169
170
171
172
173
174
175
176 @JsonProperty("code")
177 public Builder code(Integer code) {
178 this.code = code;
179 return this;
180 }
181
182
183
184
185
186
187
188 public Builder description(LocalizableString description) {
189 this.description = description;
190 return this;
191 }
192
193
194
195
196
197
198
199 @JsonProperty("description")
200 public Builder description(String description) {
201 this.description = new LocalizableString(description);
202 return this;
203 }
204
205
206
207
208
209
210
211 @JsonProperty("schema")
212 public Builder schema(Schema schema) {
213 this.schema = schema;
214 return this;
215 }
216
217
218
219
220
221
222
223 @JsonProperty("$ref")
224 public Builder reference(Reference reference) {
225 this.reference = reference;
226 return this;
227 }
228
229
230
231
232
233
234 public ApiError build() {
235 return new ApiError(this);
236 }
237 }
238
239
240
241
242
243
244
245
246 private static class ErrorComparator implements Comparator<ApiError> {
247 @Override
248 public int compare(final ApiError o1, final ApiError o2) {
249 if (o1.getReference() != null) {
250 return o2.getReference() != null
251 ? o1.getReference().getValue().compareTo(o2.getReference().getValue())
252 : 1;
253 }
254 if (o2.getReference() != null) {
255 return -1;
256 }
257 final int codeCompare = o1.code.compareTo(o2.code);
258 if (codeCompare == 0) {
259 return o1.description.toString().compareTo(o2.description.toString());
260 }
261 return codeCompare;
262 }
263 }
264 }