001/* 002 * #%L 003 * HAPI FHIR - Core Library 004 * %% 005 * Copyright (C) 2014 - 2023 Smile CDR, Inc. 006 * %% 007 * Licensed under the Apache License, Version 2.0 (the "License"); 008 * you may not use this file except in compliance with the License. 009 * You may obtain a copy of the License at 010 * 011 * http://www.apache.org/licenses/LICENSE-2.0 012 * 013 * Unless required by applicable law or agreed to in writing, software 014 * distributed under the License is distributed on an "AS IS" BASIS, 015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 016 * See the License for the specific language governing permissions and 017 * limitations under the License. 018 * #L% 019 */ 020package ca.uhn.fhir.util; 021 022import ca.uhn.fhir.context.BaseRuntimeChildDefinition; 023import ca.uhn.fhir.context.BaseRuntimeElementCompositeDefinition; 024import ca.uhn.fhir.context.BaseRuntimeElementDefinition; 025import ca.uhn.fhir.context.FhirContext; 026import ca.uhn.fhir.context.RuntimeResourceDefinition; 027import ca.uhn.fhir.i18n.Msg; 028import ca.uhn.fhir.model.api.annotation.Description; 029import ca.uhn.fhir.model.primitive.StringDt; 030import org.apache.commons.lang3.Validate; 031import org.hl7.fhir.instance.model.api.IBase; 032import org.hl7.fhir.instance.model.api.IBaseDatatype; 033import org.hl7.fhir.instance.model.api.IBaseParameters; 034import org.hl7.fhir.instance.model.api.IBaseReference; 035import org.hl7.fhir.instance.model.api.IBaseResource; 036import org.hl7.fhir.instance.model.api.IPrimitiveType; 037 038import javax.annotation.Nullable; 039import java.lang.annotation.Annotation; 040import java.lang.reflect.AnnotatedElement; 041import java.math.BigDecimal; 042import java.util.ArrayList; 043import java.util.Arrays; 044import java.util.Collection; 045import java.util.List; 046import java.util.Optional; 047import java.util.function.Function; 048import java.util.stream.Collectors; 049 050import static org.apache.commons.lang3.StringUtils.defaultIfBlank; 051import static org.apache.commons.lang3.StringUtils.isBlank; 052 053/** 054 * Utilities for dealing with parameters resources in a version indepenedent way 055 */ 056public class ParametersUtil { 057 058 public static Optional<String> getNamedParameterValueAsString(FhirContext theCtx, IBaseParameters theParameters, String theParameterName) { 059 Function<IPrimitiveType<?>, String> mapper = t -> defaultIfBlank(t.getValueAsString(), null); 060 return extractNamedParameters(theCtx, theParameters, theParameterName, mapper).stream().findFirst(); 061 } 062 063 public static List<String> getNamedParameterValuesAsString(FhirContext theCtx, IBaseParameters theParameters, String theParameterName) { 064 Function<IPrimitiveType<?>, String> mapper = t -> defaultIfBlank(t.getValueAsString(), null); 065 return extractNamedParameters(theCtx, theParameters, theParameterName, mapper); 066 } 067 068 public static List<Integer> getNamedParameterValuesAsInteger(FhirContext theCtx, IBaseParameters theParameters, String theParameterName) { 069 Function<IPrimitiveType<?>, Integer> mapper = t -> (Integer) t.getValue(); 070 return extractNamedParameters(theCtx, theParameters, theParameterName, mapper); 071 } 072 073 public static Optional<Integer> getNamedParameterValueAsInteger(FhirContext theCtx, IBaseParameters theParameters, String theParameterName) { 074 return getNamedParameterValuesAsInteger(theCtx, theParameters, theParameterName).stream().findFirst(); 075 } 076 077 public static Optional<IBase> getNamedParameter(FhirContext theCtx, IBaseResource theParameters, String theParameterName) { 078 return getNamedParameters(theCtx, theParameters, theParameterName).stream().findFirst(); 079 } 080 081 public static List<IBase> getNamedParameters(FhirContext theCtx, IBaseResource theParameters, String theParameterName) { 082 Validate.notNull(theParameters, "theParameters must not be null"); 083 RuntimeResourceDefinition resDef = theCtx.getResourceDefinition(theParameters.getClass()); 084 BaseRuntimeChildDefinition parameterChild = resDef.getChildByName("parameter"); 085 List<IBase> parameterReps = parameterChild.getAccessor().getValues(theParameters); 086 087 return parameterReps 088 .stream() 089 .filter(param -> { 090 BaseRuntimeElementCompositeDefinition<?> nextParameterDef = (BaseRuntimeElementCompositeDefinition<?>) theCtx.getElementDefinition(param.getClass()); 091 BaseRuntimeChildDefinition nameChild = nextParameterDef.getChildByName("name"); 092 List<IBase> nameValues = nameChild.getAccessor().getValues(param); 093 Optional<? extends IPrimitiveType<?>> nameValue = nameValues 094 .stream() 095 .filter(t -> t instanceof IPrimitiveType<?>) 096 .map(t -> ((IPrimitiveType<?>) t)) 097 .findFirst(); 098 return nameValue.isPresent() && theParameterName.equals(nameValue.get().getValueAsString()); 099 }) 100 .collect(Collectors.toList()); 101 102 } 103 104 public static Optional<IBase> getParameterPart(FhirContext theCtx, IBase theParameter, String theParameterName) { 105 BaseRuntimeElementCompositeDefinition<?> nextParameterDef = (BaseRuntimeElementCompositeDefinition<?>) theCtx.getElementDefinition(theParameter.getClass()); 106 BaseRuntimeChildDefinition valueChild = nextParameterDef.getChildByName("part"); 107 List<IBase> parts = valueChild.getAccessor().getValues(theParameter); 108 109 for (IBase nextPart : parts) { 110 Optional<IPrimitiveType> name = theCtx.newTerser().getSingleValue(nextPart, "name", IPrimitiveType.class); 111 if (name.isPresent() && theParameterName.equals(name.get().getValueAsString())) { 112 return Optional.of(nextPart); 113 } 114 } 115 116 return Optional.empty(); 117 } 118 119 public static Optional<IBase> getParameterPartValue(FhirContext theCtx, IBase theParameter, String theParameterName) { 120 Optional<IBase> part = getParameterPart(theCtx, theParameter, theParameterName); 121 if (part.isPresent()) { 122 return theCtx.newTerser().getSingleValue(part.get(), "value[x]", IBase.class); 123 } else { 124 return Optional.empty(); 125 } 126 } 127 128 public static String getParameterPartValueAsString(FhirContext theCtx, IBase theParameter, String theParameterName) { 129 return getParameterPartValue(theCtx, theParameter, theParameterName).map(t -> (IPrimitiveType<?>) t).map(t -> t.getValueAsString()).orElse(null); 130 } 131 132 private static <T> List<T> extractNamedParameters(FhirContext theCtx, IBaseParameters theParameters, String theParameterName, Function<IPrimitiveType<?>, T> theMapper) { 133 List<T> retVal = new ArrayList<>(); 134 135 List<IBase> namedParameters = getNamedParameters(theCtx, theParameters, theParameterName); 136 for (IBase nextParameter : namedParameters) { 137 BaseRuntimeElementCompositeDefinition<?> nextParameterDef = (BaseRuntimeElementCompositeDefinition<?>) theCtx.getElementDefinition(nextParameter.getClass()); 138 BaseRuntimeChildDefinition valueChild = nextParameterDef.getChildByName("value[x]"); 139 List<IBase> valueValues = valueChild.getAccessor().getValues(nextParameter); 140 valueValues 141 .stream() 142 .filter(t -> t instanceof IPrimitiveType<?>) 143 .map(t -> ((IPrimitiveType<?>) t)) 144 .map(theMapper) 145 .filter(t -> t != null) 146 .forEach(retVal::add); 147 148 } 149 return retVal; 150 } 151 152 private static void addClientParameter(FhirContext theContext, Object theValue, IBaseResource theTargetResource, BaseRuntimeChildDefinition paramChild, BaseRuntimeElementCompositeDefinition<?> paramChildElem, String theName) { 153 Validate.notNull(theValue, "theValue must not be null"); 154 155 if (theValue instanceof IBaseResource) { 156 IBase parameter = createParameterRepetition(theContext, theTargetResource, paramChild, paramChildElem, theName); 157 paramChildElem.getChildByName("resource").getMutator().addValue(parameter, (IBaseResource) theValue); 158 } else if (theValue instanceof IBaseDatatype) { 159 IBase parameter = createParameterRepetition(theContext, theTargetResource, paramChild, paramChildElem, theName); 160 paramChildElem.getChildByName("value[x]").getMutator().addValue(parameter, (IBaseDatatype) theValue); 161 } else if (theValue instanceof Collection) { 162 Collection<?> collection = (Collection<?>) theValue; 163 for (Object next : collection) { 164 addClientParameter(theContext, next, theTargetResource, paramChild, paramChildElem, theName); 165 } 166 } else { 167 throw new IllegalArgumentException(Msg.code(1806) + "Don't know how to handle value of type " + theValue.getClass() + " for parameter " + theName); 168 } 169 } 170 171 /** 172 * Add a parameter value to a Parameters resource 173 * 174 * @param theContext The FhirContext 175 * @param theParameters The Parameters resource 176 * @param theName The parametr name 177 * @param theValue The parameter value (can be a {@link IBaseResource resource} or a {@link IBaseDatatype datatype}) 178 */ 179 public static void addParameterToParameters(FhirContext theContext, IBaseParameters theParameters, String theName, Object theValue) { 180 RuntimeResourceDefinition def = theContext.getResourceDefinition(theParameters); 181 BaseRuntimeChildDefinition paramChild = def.getChildByName("parameter"); 182 BaseRuntimeElementCompositeDefinition<?> paramChildElem = (BaseRuntimeElementCompositeDefinition<?>) paramChild.getChildByName("parameter"); 183 184 addClientParameter(theContext, theValue, theParameters, paramChild, paramChildElem, theName); 185 } 186 187 /** 188 * Add a parameter value to a Parameters resource 189 * 190 * @param theContext The FhirContext 191 * @param theParameters The Parameters resource 192 * @param theName The parameter name 193 * @param thePrimitiveDatatype The datatype, e.g. "string", or "uri" 194 * @param theValue The value 195 */ 196 public static void addParameterToParameters(FhirContext theContext, IBaseParameters theParameters, String theName, String thePrimitiveDatatype, String theValue) { 197 Validate.notBlank(thePrimitiveDatatype, "thePrimitiveDatatype must not be null or empty"); 198 199 BaseRuntimeElementDefinition<?> datatypeDef = theContext.getElementDefinition(thePrimitiveDatatype); 200 IPrimitiveType<?> value = (IPrimitiveType<?>) datatypeDef.newInstance(); 201 value.setValueAsString(theValue); 202 203 addParameterToParameters(theContext, theParameters, theName, value); 204 } 205 206 private static IBase createParameterRepetition(FhirContext theContext, IBaseResource theTargetResource, BaseRuntimeChildDefinition paramChild, BaseRuntimeElementCompositeDefinition<?> paramChildElem, String theName) { 207 IBase parameter = paramChildElem.newInstance(); 208 paramChild.getMutator().addValue(theTargetResource, parameter); 209 IPrimitiveType<?> value; 210 value = createString(theContext, theName); 211 paramChildElem.getChildByName("name").getMutator().addValue(parameter, value); 212 return parameter; 213 } 214 215 public static IPrimitiveType<?> createString(FhirContext theContext, String theValue) { 216 IPrimitiveType<?> value; 217 if (theContext.getVersion().getVersion().isRi()) { 218 value = (IPrimitiveType<?>) theContext.getElementDefinition("string").newInstance(theValue); 219 } else { 220 value = new StringDt(theValue); 221 } 222 return value; 223 } 224 225 public static IPrimitiveType<?> createUri(FhirContext theContext, String theValue) { 226 IPrimitiveType<?> value = (IPrimitiveType<?>) theContext.getElementDefinition("uri").newInstance(theValue); 227 return value; 228 } 229 230 public static IPrimitiveType<?> createCode(FhirContext theContext, String theValue) { 231 IPrimitiveType<?> value = (IPrimitiveType<?>) theContext.getElementDefinition("code").newInstance(theValue); 232 return value; 233 } 234 235 public static IBaseParameters newInstance(FhirContext theContext) { 236 Validate.notNull(theContext, "theContext must not be null"); 237 return (IBaseParameters) theContext.getResourceDefinition("Parameters").newInstance(); 238 } 239 240 @SuppressWarnings("unchecked") 241 public static void addParameterToParametersBoolean(FhirContext theCtx, IBaseParameters theParameters, String theName, boolean theValue) { 242 addParameterToParameters(theCtx, theParameters, theName, theCtx.getPrimitiveBoolean(theValue)); 243 } 244 245 @SuppressWarnings("unchecked") 246 public static void addParameterToParametersCode(FhirContext theCtx, IBaseParameters theParameters, String theName, String theValue) { 247 IPrimitiveType<String> value = (IPrimitiveType<String>) theCtx.getElementDefinition("code").newInstance(); 248 value.setValue(theValue); 249 addParameterToParameters(theCtx, theParameters, theName, value); 250 } 251 252 @SuppressWarnings("unchecked") 253 public static void addParameterToParametersInteger(FhirContext theCtx, IBaseParameters theParameters, String theName, int theValue) { 254 IPrimitiveType<Integer> count = (IPrimitiveType<Integer>) theCtx.getElementDefinition("integer").newInstance(); 255 count.setValue(theValue); 256 addParameterToParameters(theCtx, theParameters, theName, count); 257 } 258 259 public static void addParameterToParametersLong(FhirContext theCtx, IBaseParameters theParameters, String theName, long theValue) { 260 addParameterToParametersDecimal(theCtx, theParameters, theName, BigDecimal.valueOf(theValue)); 261 } 262 263 public static void addParameterToParametersDecimal(FhirContext theCtx, IBaseParameters theParameters, String theName, BigDecimal theValue) { 264 IPrimitiveType<BigDecimal> count = (IPrimitiveType<BigDecimal>) theCtx.getElementDefinition("decimal").newInstance(); 265 count.setValue(theValue); 266 addParameterToParameters(theCtx, theParameters, theName, count); 267 } 268 269 public static void addParameterToParametersReference(FhirContext theCtx, IBaseParameters theParameters, String theName, String theReference) { 270 IBaseReference target = (IBaseReference) theCtx.getElementDefinition("reference").newInstance(); 271 target.setReference(theReference); 272 addParameterToParameters(theCtx, theParameters, theName, target); 273 } 274 275 @SuppressWarnings("unchecked") 276 public static void addParameterToParametersString(FhirContext theCtx, IBaseParameters theParameters, String theName, String theValue) { 277 IPrimitiveType<String> value = (IPrimitiveType<String>) theCtx.getElementDefinition("string").newInstance(); 278 value.setValue(theValue); 279 addParameterToParameters(theCtx, theParameters, theName, value); 280 } 281 282 @SuppressWarnings("unchecked") 283 public static void addParameterToParametersUri(FhirContext theCtx, IBaseParameters theParameters, String theName, String theValue) { 284 IPrimitiveType<String> value = (IPrimitiveType<String>) theCtx.getElementDefinition("uri").newInstance(); 285 value.setValue(theValue); 286 addParameterToParameters(theCtx, theParameters, theName, value); 287 288 } 289 290 /** 291 * Add a parameter with no value (typically because we'll be adding sub-parameters) 292 */ 293 public static IBase addParameterToParameters(FhirContext theContext, IBaseParameters theParameters, String theName) { 294 RuntimeResourceDefinition def = theContext.getResourceDefinition(theParameters); 295 BaseRuntimeChildDefinition paramChild = def.getChildByName("parameter"); 296 BaseRuntimeElementCompositeDefinition<?> paramChildElem = (BaseRuntimeElementCompositeDefinition<?>) paramChild.getChildByName("parameter"); 297 298 return createParameterRepetition(theContext, theParameters, paramChild, paramChildElem, theName); 299 } 300 301 public static void addPartCode(FhirContext theContext, IBase theParameter, String theName, String theCode) { 302 IPrimitiveType<String> value = (IPrimitiveType<String>) theContext.getElementDefinition("code").newInstance(); 303 value.setValue(theCode); 304 305 addPart(theContext, theParameter, theName, value); 306 } 307 308 public static void addPartInteger(FhirContext theContext, IBase theParameter, String theName, Integer theInteger) { 309 IPrimitiveType<Integer> value = (IPrimitiveType<Integer>) theContext.getElementDefinition("integer").newInstance(); 310 value.setValue(theInteger); 311 312 addPart(theContext, theParameter, theName, value); 313 } 314 315 public static void addPartString(FhirContext theContext, IBase theParameter, String theName, String theValue) { 316 IPrimitiveType<String> value = (IPrimitiveType<String>) theContext.getElementDefinition("string").newInstance(); 317 value.setValue(theValue); 318 319 addPart(theContext, theParameter, theName, value); 320 } 321 322 public static void addPartUrl(FhirContext theContext, IBase theParameter, String theName, String theCode) { 323 IPrimitiveType<String> value = (IPrimitiveType<String>) theContext.getElementDefinition("url").newInstance(); 324 value.setValue(theCode); 325 326 addPart(theContext, theParameter, theName, value); 327 } 328 329 public static void addPartBoolean(FhirContext theContext, IBase theParameter, String theName, Boolean theValue) { 330 addPart(theContext, theParameter, theName, theContext.getPrimitiveBoolean(theValue)); 331 } 332 333 public static void addPartDecimal(FhirContext theContext, IBase theParameter, String theName, Double theValue) { 334 IPrimitiveType<BigDecimal> value = (IPrimitiveType<BigDecimal>) theContext.getElementDefinition("decimal").newInstance(); 335 value.setValue(theValue == null ? null : new BigDecimal(theValue)); 336 337 addPart(theContext, theParameter, theName, value); 338 } 339 340 public static void addPartCoding(FhirContext theContext, IBase theParameter, String theName, String theSystem, String theCode, String theDisplay) { 341 IBase coding = theContext.getElementDefinition("coding").newInstance(); 342 343 BaseRuntimeElementCompositeDefinition<?> codingDef = (BaseRuntimeElementCompositeDefinition<?>) theContext.getElementDefinition(coding.getClass()); 344 codingDef.getChildByName("system").getMutator().addValue(coding, createUri(theContext, theSystem)); 345 codingDef.getChildByName("code").getMutator().addValue(coding, createCode(theContext, theCode)); 346 codingDef.getChildByName("display").getMutator().addValue(coding, createString(theContext, theDisplay)); 347 348 addPart(theContext, theParameter, theName, coding); 349 } 350 351 public static void addPart(FhirContext theContext, IBase theParameter, String theName, IBase theValue) { 352 BaseRuntimeElementCompositeDefinition<?> def = (BaseRuntimeElementCompositeDefinition<?>) theContext.getElementDefinition(theParameter.getClass()); 353 BaseRuntimeChildDefinition partChild = def.getChildByName("part"); 354 355 BaseRuntimeElementCompositeDefinition<?> partChildElem = (BaseRuntimeElementCompositeDefinition<?>) partChild.getChildByName("part"); 356 IBase part = partChildElem.newInstance(); 357 partChild.getMutator().addValue(theParameter, part); 358 359 IPrimitiveType<String> name = (IPrimitiveType<String>) theContext.getElementDefinition("string").newInstance(); 360 name.setValue(theName); 361 partChildElem.getChildByName("name").getMutator().addValue(part, name); 362 363 if (theValue instanceof IBaseResource) { 364 partChildElem.getChildByName("resource").getMutator().addValue(part, theValue); 365 } else { 366 partChildElem.getChildByName("value[x]").getMutator().addValue(part, theValue); 367 } 368 } 369 370 public static void addPartResource(FhirContext theContext, IBase theParameter, String theName, IBaseResource theValue) { 371 BaseRuntimeElementCompositeDefinition<?> def = (BaseRuntimeElementCompositeDefinition<?>) theContext.getElementDefinition(theParameter.getClass()); 372 BaseRuntimeChildDefinition partChild = def.getChildByName("part"); 373 374 BaseRuntimeElementCompositeDefinition<?> partChildElem = (BaseRuntimeElementCompositeDefinition<?>) partChild.getChildByName("part"); 375 IBase part = partChildElem.newInstance(); 376 partChild.getMutator().addValue(theParameter, part); 377 378 IPrimitiveType<String> name = (IPrimitiveType<String>) theContext.getElementDefinition("string").newInstance(); 379 name.setValue(theName); 380 partChildElem.getChildByName("name").getMutator().addValue(part, name); 381 382 partChildElem.getChildByName("resource").getMutator().addValue(part, theValue); 383 } 384 385 public static List<String> getNamedParameterPartAsString(FhirContext theCtx, IBaseParameters theParameters, String thePartName, String theParameterName) { 386 return extractNamedParameterPartsAsString(theCtx, theParameters, thePartName, theParameterName); 387 } 388 389 // TODO KHS need to consolidate duplicated functionality that came in from different branches 390 private static List<String> extractNamedParameterPartsAsString(FhirContext theCtx, IBaseParameters theParameters, String thePartName, String theParameterName) { 391 List<IBase> parameterReps = getParameterReps(theCtx, theParameters); 392 393 List<String> retVal = new ArrayList<>(); 394 395 for (IBase nextParameter : parameterReps) { 396 BaseRuntimeElementCompositeDefinition<?> nextParameterDef = (BaseRuntimeElementCompositeDefinition<?>) theCtx.getElementDefinition(nextParameter.getClass()); 397 Optional<? extends IPrimitiveType<?>> nameValue = getNameValue(nextParameter, nextParameterDef); 398 if (!nameValue.isPresent() || !thePartName.equals(nameValue.get().getValueAsString())) { 399 continue; 400 } 401 402 BaseRuntimeChildDefinition partChild = nextParameterDef.getChildByName("part"); 403 List<IBase> partValues = partChild.getAccessor().getValues(nextParameter); 404 for (IBase partValue : partValues) { 405 BaseRuntimeElementCompositeDefinition<?> partParameterDef = (BaseRuntimeElementCompositeDefinition<?>) theCtx.getElementDefinition(partValue.getClass()); 406 Optional<? extends IPrimitiveType<?>> partNameValue = getNameValue(partValue, partParameterDef); 407 if (!partNameValue.isPresent() || !theParameterName.equals(partNameValue.get().getValueAsString())) { 408 continue; 409 } 410 BaseRuntimeChildDefinition valueChild = partParameterDef.getChildByName("value[x]"); 411 List<IBase> valueValues = valueChild.getAccessor().getValues(partValue); 412 valueValues 413 .stream() 414 .filter(t -> t instanceof IPrimitiveType<?>) 415 .map(t -> ((IPrimitiveType<String>) t)) 416 .map(t -> defaultIfBlank(t.getValueAsString(), null)) 417 .filter(t -> t != null) 418 .forEach(retVal::add); 419 420 } 421 } 422 return retVal; 423 } 424 425 private static List<IBase> getParameterReps(FhirContext theCtx, IBaseParameters theParameters) { 426 Validate.notNull(theParameters, "theParameters must not be null"); 427 RuntimeResourceDefinition resDef = theCtx.getResourceDefinition(theParameters.getClass()); 428 BaseRuntimeChildDefinition parameterChild = resDef.getChildByName("parameter"); 429 return parameterChild.getAccessor().getValues(theParameters); 430 } 431 432 private static Optional<? extends IPrimitiveType<?>> getNameValue(IBase nextParameter, BaseRuntimeElementCompositeDefinition<?> theNextParameterDef) { 433 BaseRuntimeChildDefinition nameChild = theNextParameterDef.getChildByName("name"); 434 List<IBase> nameValues = nameChild.getAccessor().getValues(nextParameter); 435 return nameValues 436 .stream() 437 .filter(t -> t instanceof IPrimitiveType<?>) 438 .map(t -> ((IPrimitiveType<?>) t)) 439 .findFirst(); 440 } 441 442 @Nullable 443 public static String extractDescription(AnnotatedElement theType) { 444 Description description = theType.getAnnotation(Description.class); 445 if (description != null) { 446 return extractDescription(description); 447 } else { 448 return null; 449 } 450 } 451 452 @Nullable 453 public static String extractDescription(Description desc) { 454 String description = desc.value(); 455 if (isBlank(description)) { 456 description = desc.formalDefinition(); 457 } 458 if (isBlank(description)) { 459 description = desc.shortDefinition(); 460 } 461 return defaultIfBlank(description, null); 462 } 463 464 @Nullable 465 public static String extractShortDefinition(AnnotatedElement theType) { 466 Description description = theType.getAnnotation(Description.class); 467 if (description != null) { 468 return defaultIfBlank(description.shortDefinition(), null); 469 } else { 470 return null; 471 } 472 } 473 474 public static String extractDescription(Annotation[] theParameterAnnotations) { 475 for (Annotation next : theParameterAnnotations) { 476 if (next instanceof Description) { 477 return extractDescription((Description)next); 478 } 479 } 480 return null; 481 } 482 483 public static List<String> extractExamples(Annotation[] theParameterAnnotations) { 484 ArrayList<String> retVal = null; 485 for (Annotation next : theParameterAnnotations) { 486 if (next instanceof Description) { 487 String[] examples = ((Description) next).example(); 488 if (examples.length > 0) { 489 if (retVal == null) { 490 retVal = new ArrayList<>(); 491 } 492 retVal.addAll(Arrays.asList(examples)); 493 } 494 } 495 } 496 return retVal; 497 } 498}