001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.juneau.rest.annotation; 018 019import static org.apache.juneau.commons.utils.CollectionUtils.*; 020import static org.apache.juneau.commons.utils.StringUtils.*; 021import static org.apache.juneau.commons.utils.Utils.*; 022 023import java.lang.annotation.*; 024import java.nio.charset.*; 025import java.util.function.*; 026 027import org.apache.juneau.*; 028import org.apache.juneau.encoders.*; 029import org.apache.juneau.http.*; 030import org.apache.juneau.commons.annotation.*; 031import org.apache.juneau.commons.reflect.*; 032import org.apache.juneau.rest.*; 033import org.apache.juneau.rest.converter.*; 034import org.apache.juneau.rest.guard.*; 035import org.apache.juneau.rest.httppart.*; 036import org.apache.juneau.rest.matcher.*; 037import org.apache.juneau.serializer.*; 038import org.apache.juneau.svl.*; 039 040/** 041 * Utility classes and methods for the {@link RestOp @RestOp} annotation. 042 * 043 * <h5 class='section'>See Also:</h5><ul> 044 * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/RestOpAnnotatedMethodBasics">@RestOp-Annotated Method Basics</a> 045 * </ul> 046 */ 047public class RestOpAnnotation { 048 /** 049 * Builder class. 050 * 051 * <h5 class='section'>See Also:</h5><ul> 052 * <li class='jm'>{@link org.apache.juneau.BeanContext.Builder#annotations(Annotation...)} 053 * </ul> 054 */ 055 @SuppressWarnings("unchecked") 056 public static class Builder extends AppliedAnnotationObject.BuilderM { 057 058 private String[] description = {}; 059 private Class<? extends RestConverter>[] converters = new Class[0]; 060 private Class<? extends RestGuard>[] guards = new Class[0]; 061 private Class<? extends RestMatcher>[] matchers = new Class[0]; 062 private Class<? extends Encoder>[] encoders = new Class[0]; 063 private Class<? extends Serializer>[] serializers = new Class[0]; 064 private Class<?>[] parsers = {}; 065 private OpSwagger swagger = OpSwaggerAnnotation.DEFAULT; 066 private String clientVersion = "", debug = "", defaultAccept = "", defaultCharset = "", defaultContentType = "", maxInput = "", method = "", rolesDeclared = "", roleGuard = "", summary = "", 067 value = ""; 068 private String[] consumes = {}, defaultRequestFormData = {}, defaultRequestQueryData = {}, defaultRequestAttributes = {}, defaultRequestHeaders = {}, defaultResponseHeaders = {}, path = {}, 069 produces = {}; 070 071 /** 072 * Constructor. 073 */ 074 protected Builder() { 075 super(RestOp.class); 076 } 077 078 /** 079 * Instantiates a new {@link RestOp @RestOp} object initialized with this builder. 080 * 081 * @return A new {@link RestOp @RestOp} object. 082 */ 083 public RestOp build() { 084 return new Object(this); 085 } 086 087 /** 088 * Sets the description property on this annotation. 089 * 090 * @param value The new value for this property. 091 * @return This object. 092 */ 093 public Builder description(String...value) { 094 description = value; 095 return this; 096 } 097 098 /** 099 * Sets the {@link RestOp#clientVersion()} property on this annotation. 100 * 101 * @param value The new value for this property. 102 * @return This object. 103 */ 104 public Builder clientVersion(String value) { 105 clientVersion = value; 106 return this; 107 } 108 109 /** 110 * Sets the {@link RestOp#consumes()} property on this annotation. 111 * 112 * @param value The new value for this property. 113 * @return This object. 114 */ 115 public Builder consumes(String...value) { 116 consumes = value; 117 return this; 118 } 119 120 /** 121 * Sets the {@link RestOp#converters()} property on this annotation. 122 * 123 * @param value The new value for this property. 124 * @return This object. 125 */ 126 @SafeVarargs 127 public final Builder converters(Class<? extends RestConverter>...value) { 128 converters = value; 129 return this; 130 } 131 132 /** 133 * Sets the {@link RestOp#debug()} property on this annotation. 134 * 135 * @param value The new value for this property. 136 * @return This object. 137 */ 138 public Builder debug(String value) { 139 debug = value; 140 return this; 141 } 142 143 /** 144 * Sets the {@link RestOp#defaultAccept()} property on this annotation. 145 * 146 * @param value The new value for this property. 147 * @return This object. 148 */ 149 public Builder defaultAccept(String value) { 150 defaultAccept = value; 151 return this; 152 } 153 154 /** 155 * Sets the {@link RestOp#defaultCharset()} property on this annotation. 156 * 157 * @param value The new value for this property. 158 * @return This object. 159 */ 160 public Builder defaultCharset(String value) { 161 defaultCharset = value; 162 return this; 163 } 164 165 /** 166 * Sets the {@link RestOp#defaultContentType()} property on this annotation. 167 * 168 * @param value The new value for this property. 169 * @return This object. 170 */ 171 public Builder defaultContentType(String value) { 172 defaultContentType = value; 173 return this; 174 } 175 176 /** 177 * Sets the {@link RestOp#defaultRequestAttributes()} property on this annotation. 178 * 179 * @param value The new value for this property. 180 * @return This object. 181 */ 182 public Builder defaultRequestAttributes(String...value) { 183 defaultRequestAttributes = value; 184 return this; 185 } 186 187 /** 188 * Sets the {@link RestOp#defaultRequestFormData()} property on this annotation. 189 * 190 * @param value The new value for this property. 191 * @return This object. 192 */ 193 public Builder defaultRequestFormData(String...value) { 194 defaultRequestFormData = value; 195 return this; 196 } 197 198 /** 199 * Sets the {@link RestOp#defaultRequestHeaders()} property on this annotation. 200 * 201 * @param value The new value for this property. 202 * @return This object. 203 */ 204 public Builder defaultRequestHeaders(String...value) { 205 defaultRequestHeaders = value; 206 return this; 207 } 208 209 /** 210 * Sets the {@link RestOp#defaultRequestQueryData()} property on this annotation. 211 * 212 * @param value The new value for this property. 213 * @return This object. 214 */ 215 public Builder defaultRequestQueryData(String...value) { 216 defaultRequestQueryData = value; 217 return this; 218 } 219 220 /** 221 * Sets the {@link RestOp#defaultResponseHeaders()} property on this annotation. 222 * 223 * @param value The new value for this property. 224 * @return This object. 225 */ 226 public Builder defaultResponseHeaders(String...value) { 227 defaultResponseHeaders = value; 228 return this; 229 } 230 231 /** 232 * Sets the {@link RestOp#encoders()} property on this annotation. 233 * 234 * @param value The new value for this property. 235 * @return This object. 236 */ 237 @SafeVarargs 238 public final Builder encoders(Class<? extends Encoder>...value) { 239 encoders = value; 240 return this; 241 } 242 243 /** 244 * Sets the {@link RestOp#guards()} property on this annotation. 245 * 246 * @param value The new value for this property. 247 * @return This object. 248 */ 249 @SafeVarargs 250 public final Builder guards(Class<? extends RestGuard>...value) { 251 guards = value; 252 return this; 253 } 254 255 /** 256 * Sets the {@link RestOp#matchers()} property on this annotation. 257 * 258 * @param value The new value for this property. 259 * @return This object. 260 */ 261 @SafeVarargs 262 public final Builder matchers(Class<? extends RestMatcher>...value) { 263 matchers = value; 264 return this; 265 } 266 267 /** 268 * Sets the {@link RestOp#maxInput()} property on this annotation. 269 * 270 * @param value The new value for this property. 271 * @return This object. 272 */ 273 public Builder maxInput(String value) { 274 maxInput = value; 275 return this; 276 } 277 278 /** 279 * Sets the {@link RestOp#method()} property on this annotation. 280 * 281 * @param value The new value for this property. 282 * @return This object. 283 */ 284 public Builder method(String value) { 285 method = value; 286 return this; 287 } 288 289 /** 290 * Sets the {@link RestOp#parsers()} property on this annotation. 291 * 292 * @param value The new value for this property. 293 * @return This object. 294 */ 295 public Builder parsers(Class<?>...value) { 296 parsers = value; 297 return this; 298 } 299 300 /** 301 * Sets the {@link RestOp#path()} property on this annotation. 302 * 303 * @param value The new value for this property. 304 * @return This object. 305 */ 306 public Builder path(String...value) { 307 path = value; 308 return this; 309 } 310 311 /** 312 * Sets the {@link RestOp#produces()} property on this annotation. 313 * 314 * @param value The new value for this property. 315 * @return This object. 316 */ 317 public Builder produces(String...value) { 318 produces = value; 319 return this; 320 } 321 322 /** 323 * Sets the {@link RestOp#roleGuard()} property on this annotation. 324 * 325 * @param value The new value for this property. 326 * @return This object. 327 */ 328 public Builder roleGuard(String value) { 329 roleGuard = value; 330 return this; 331 } 332 333 /** 334 * Sets the {@link RestOp#rolesDeclared()} property on this annotation. 335 * 336 * @param value The new value for this property. 337 * @return This object. 338 */ 339 public Builder rolesDeclared(String value) { 340 rolesDeclared = value; 341 return this; 342 } 343 344 /** 345 * Sets the {@link RestOp#serializers()} property on this annotation. 346 * 347 * @param value The new value for this property. 348 * @return This object. 349 */ 350 @SafeVarargs 351 public final Builder serializers(Class<? extends Serializer>...value) { 352 serializers = value; 353 return this; 354 } 355 356 /** 357 * Sets the {@link RestOp#summary()} property on this annotation. 358 * 359 * @param value The new value for this property. 360 * @return This object. 361 */ 362 public Builder summary(String value) { 363 summary = value; 364 return this; 365 } 366 367 /** 368 * Sets the {@link RestOp#swagger()} property on this annotation. 369 * 370 * @param value The new value for this property. 371 * @return This object. 372 */ 373 public Builder swagger(OpSwagger value) { 374 swagger = value; 375 return this; 376 } 377 378 /** 379 * Sets the {@link RestOp#value()} property on this annotation. 380 * 381 * @param value The new value for this property. 382 * @return This object. 383 */ 384 public Builder value(String value) { 385 this.value = value; 386 return this; 387 } 388 389 @Override /* Overridden from AppliedAnnotationObject.Builder */ 390 public Builder on(String...value) { 391 super.on(value); 392 return this; 393 } 394 395 @Override /* Overridden from AppliedAnnotationObject.BuilderM */ 396 public Builder on(java.lang.reflect.Method...value) { 397 super.on(value); 398 return this; 399 } 400 401 @Override /* Overridden from AppliedAnnotationObject.BuilderM */ 402 public Builder on(MethodInfo...value) { 403 super.on(value); 404 return this; 405 } 406 407 } 408 409 /** 410 * Applies {@link RestOp} annotations to a {@link org.apache.juneau.rest.RestOpContext.Builder}. 411 */ 412 public static class RestOpContextApply extends AnnotationApplier<RestOp,RestOpContext.Builder> { 413 414 /** 415 * Constructor. 416 * 417 * @param vr The resolver for resolving values in annotations. 418 */ 419 public RestOpContextApply(VarResolverSession vr) { 420 super(RestOp.class, RestOpContext.Builder.class, vr); 421 } 422 423 @Override 424 public void apply(AnnotationInfo<RestOp> ai, RestOpContext.Builder b) { 425 RestOp a = ai.inner(); 426 427 classes(a.serializers()).ifPresent(x -> b.serializers().set(x)); 428 classes(a.parsers()).ifPresent(x -> b.parsers().set(x)); 429 classes(a.encoders()).ifPresent(x -> b.encoders().set(x)); 430 stream(a.produces()).map(MediaType::of).forEach(x -> b.produces(x)); 431 stream(a.consumes()).map(MediaType::of).forEach(x -> b.consumes(x)); 432 stream(a.defaultRequestHeaders()).map(HttpHeaders::stringHeader).forEach(x -> b.defaultRequestHeaders().setDefault(x)); 433 stream(a.defaultResponseHeaders()).map(HttpHeaders::stringHeader).forEach(x -> b.defaultResponseHeaders().setDefault(x)); 434 stream(a.defaultRequestAttributes()).map(BasicNamedAttribute::ofPair).forEach(x -> b.defaultRequestAttributes().add(x)); 435 stream(a.defaultRequestQueryData()).map(HttpParts::basicPart).forEach(x -> b.defaultRequestQueryData().setDefault(x)); 436 stream(a.defaultRequestFormData()).map(HttpParts::basicPart).forEach(x -> b.defaultRequestFormData().setDefault(x)); 437 string(a.defaultAccept()).map(HttpHeaders::accept).ifPresent(x -> b.defaultRequestHeaders().setDefault(x)); 438 string(a.defaultContentType()).map(HttpHeaders::contentType).ifPresent(x -> b.defaultRequestHeaders().setDefault(x)); 439 b.converters().append(a.converters()); 440 b.guards().append(a.guards()); 441 b.matchers().append(a.matchers()); 442 string(a.clientVersion()).ifPresent(x -> b.clientVersion(x)); 443 string(a.defaultCharset()).map(Charset::forName).ifPresent(x -> b.defaultCharset(x)); 444 string(a.maxInput()).ifPresent(x -> b.maxInput(x)); 445 stream(a.path()).forEach(x -> b.path(x)); 446 cdl(a.rolesDeclared()).forEach(x -> b.rolesDeclared(x)); 447 string(a.roleGuard()).ifPresent(x -> b.roleGuard(x)); 448 449 string(a.method()).ifPresent(x -> b.httpMethod(x)); 450 string(a.debug()).map(Enablement::fromString).ifPresent(x -> b.debug(x)); 451 452 var v = trim(string(a.value()).orElse(null)); 453 if (nn(v)) { 454 var i = v.indexOf(' '); 455 if (i == -1) { 456 b.httpMethod(v); 457 } else { 458 b.httpMethod(v.substring(0, i).trim()); 459 b.path(v.substring(i).trim()); 460 } 461 } 462 } 463 464 } 465 466 private static class Object extends AppliedAnnotationObject implements RestOp { 467 468 private final String[] description; 469 private final Class<? extends RestConverter>[] converters; 470 private final Class<? extends RestGuard>[] guards; 471 private final Class<? extends RestMatcher>[] matchers; 472 private final Class<? extends Encoder>[] encoders; 473 private final Class<? extends Serializer>[] serializers; 474 private final Class<?>[] parsers; 475 private final OpSwagger swagger; 476 private final String clientVersion, debug, defaultAccept, defaultCharset, defaultContentType, maxInput, method, rolesDeclared, roleGuard, summary, value; 477 private final String[] consumes, defaultRequestFormData, defaultRequestQueryData, defaultRequestAttributes, defaultRequestHeaders, defaultResponseHeaders, path, produces; 478 479 Object(RestOpAnnotation.Builder b) { 480 super(b); 481 description = copyOf(b.description); 482 clientVersion = b.clientVersion; 483 consumes = copyOf(b.consumes); 484 converters = copyOf(b.converters); 485 debug = b.debug; 486 defaultAccept = b.defaultAccept; 487 defaultCharset = b.defaultCharset; 488 defaultContentType = b.defaultContentType; 489 defaultRequestFormData = copyOf(b.defaultRequestFormData); 490 defaultRequestQueryData = copyOf(b.defaultRequestQueryData); 491 defaultRequestAttributes = copyOf(b.defaultRequestAttributes); 492 defaultRequestHeaders = copyOf(b.defaultRequestHeaders); 493 defaultResponseHeaders = copyOf(b.defaultResponseHeaders); 494 encoders = copyOf(b.encoders); 495 guards = copyOf(b.guards); 496 matchers = copyOf(b.matchers); 497 maxInput = b.maxInput; 498 method = b.method; 499 parsers = copyOf(b.parsers); 500 path = copyOf(b.path); 501 produces = copyOf(b.produces); 502 roleGuard = b.roleGuard; 503 rolesDeclared = b.rolesDeclared; 504 serializers = copyOf(b.serializers); 505 summary = b.summary; 506 swagger = b.swagger; 507 value = b.value; 508 } 509 510 @Override /* Overridden from RestOp */ 511 public String clientVersion() { 512 return clientVersion; 513 } 514 515 @Override /* Overridden from RestOp */ 516 public String[] consumes() { 517 return consumes; 518 } 519 520 @Override /* Overridden from RestOp */ 521 public Class<? extends RestConverter>[] converters() { 522 return converters; 523 } 524 525 @Override /* Overridden from RestOp */ 526 public String debug() { 527 return debug; 528 } 529 530 @Override /* Overridden from RestOp */ 531 public String defaultAccept() { 532 return defaultAccept; 533 } 534 535 @Override /* Overridden from RestOp */ 536 public String defaultCharset() { 537 return defaultCharset; 538 } 539 540 @Override /* Overridden from RestOp */ 541 public String defaultContentType() { 542 return defaultContentType; 543 } 544 545 @Override /* Overridden from RestOp */ 546 public String[] defaultRequestAttributes() { 547 return defaultRequestAttributes; 548 } 549 550 @Override /* Overridden from RestOp */ 551 public String[] defaultRequestFormData() { 552 return defaultRequestFormData; 553 } 554 555 @Override /* Overridden from RestOp */ 556 public String[] defaultRequestHeaders() { 557 return defaultRequestHeaders; 558 } 559 560 @Override /* Overridden from RestOp */ 561 public String[] defaultRequestQueryData() { 562 return defaultRequestQueryData; 563 } 564 565 @Override /* Overridden from RestOp */ 566 public String[] defaultResponseHeaders() { 567 return defaultResponseHeaders; 568 } 569 570 @Override /* Overridden from RestOp */ 571 public Class<? extends Encoder>[] encoders() { 572 return encoders; 573 } 574 575 @Override /* Overridden from RestOp */ 576 public Class<? extends RestGuard>[] guards() { 577 return guards; 578 } 579 580 @Override /* Overridden from RestOp */ 581 public Class<? extends RestMatcher>[] matchers() { 582 return matchers; 583 } 584 585 @Override /* Overridden from RestOp */ 586 public String maxInput() { 587 return maxInput; 588 } 589 590 @Override /* Overridden from RestOp */ 591 public String method() { 592 return method; 593 } 594 595 @Override /* Overridden from RestOp */ 596 public Class<?>[] parsers() { 597 return parsers; 598 } 599 600 @Override /* Overridden from RestOp */ 601 public String[] path() { 602 return path; 603 } 604 605 @Override /* Overridden from RestOp */ 606 public String[] produces() { 607 return produces; 608 } 609 610 @Override /* Overridden from RestOp */ 611 public String roleGuard() { 612 return roleGuard; 613 } 614 615 @Override /* Overridden from RestOp */ 616 public String rolesDeclared() { 617 return rolesDeclared; 618 } 619 620 @Override /* Overridden from RestOp */ 621 public Class<? extends Serializer>[] serializers() { 622 return serializers; 623 } 624 625 @Override /* Overridden from RestOp */ 626 public String summary() { 627 return summary; 628 } 629 630 @Override /* Overridden from RestOp */ 631 public OpSwagger swagger() { 632 return swagger; 633 } 634 635 @Override /* Overridden from RestOp */ 636 public String value() { 637 return value; 638 } 639 640 @Override /* Overridden from annotation */ 641 public String[] description() { 642 return description; 643 } 644 } 645 646 /** Default value */ 647 public static final RestOp DEFAULT = create().build(); 648 /** 649 * Predicate that can be used to filter annotation streams. 650 * 651 * <p> 652 * Example: <c>classInfo.getAnnotations().stream().filter(REST_OP_GROUP)</c> 653 */ 654 public static final Predicate<AnnotationInfo<?>> REST_OP_GROUP = x -> x.isInGroup(RestOp.class); 655 656 /** 657 * Instantiates a new builder for this class. 658 * 659 * @return A new builder object. 660 */ 661 public static Builder create() { 662 return new Builder(); 663 } 664}