001/*
002 * #%L
003 * HAPI FHIR - Core Library
004 * %%
005 * Copyright (C) 2014 - 2024 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 jakarta.annotation.Nullable;
031import org.apache.commons.lang3.Validate;
032import org.hl7.fhir.instance.model.api.IBase;
033import org.hl7.fhir.instance.model.api.IBaseDatatype;
034import org.hl7.fhir.instance.model.api.IBaseParameters;
035import org.hl7.fhir.instance.model.api.IBaseReference;
036import org.hl7.fhir.instance.model.api.IBaseResource;
037import org.hl7.fhir.instance.model.api.IPrimitiveType;
038
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(
059                        FhirContext theCtx, IBaseParameters theParameters, String theParameterName) {
060                Function<IPrimitiveType<?>, String> mapper = t -> defaultIfBlank(t.getValueAsString(), null);
061                return extractNamedParameters(theCtx, theParameters, theParameterName, mapper).stream()
062                                .findFirst();
063        }
064
065        public static List<String> getNamedParameterValuesAsString(
066                        FhirContext theCtx, IBaseParameters theParameters, String theParameterName) {
067                Function<IPrimitiveType<?>, String> mapper = t -> defaultIfBlank(t.getValueAsString(), null);
068                return extractNamedParameters(theCtx, theParameters, theParameterName, mapper);
069        }
070
071        public static List<Integer> getNamedParameterValuesAsInteger(
072                        FhirContext theCtx, IBaseParameters theParameters, String theParameterName) {
073                Function<IPrimitiveType<?>, Integer> mapper = t -> (Integer) t.getValue();
074                return extractNamedParameters(theCtx, theParameters, theParameterName, mapper);
075        }
076
077        public static Optional<Integer> getNamedParameterValueAsInteger(
078                        FhirContext theCtx, IBaseParameters theParameters, String theParameterName) {
079                return getNamedParameterValuesAsInteger(theCtx, theParameters, theParameterName).stream()
080                                .findFirst();
081        }
082
083        public static Optional<IBase> getNamedParameter(
084                        FhirContext theCtx, IBaseResource theParameters, String theParameterName) {
085                return getNamedParameters(theCtx, theParameters, theParameterName).stream()
086                                .findFirst();
087        }
088
089        public static List<IBase> getNamedParameters(
090                        FhirContext theCtx, IBaseResource theParameters, String theParameterName) {
091                Validate.notNull(theParameters, "theParameters must not be null");
092                RuntimeResourceDefinition resDef = theCtx.getResourceDefinition(theParameters.getClass());
093                BaseRuntimeChildDefinition parameterChild = resDef.getChildByName("parameter");
094                List<IBase> parameterReps = parameterChild.getAccessor().getValues(theParameters);
095
096                return parameterReps.stream()
097                                .filter(param -> {
098                                        BaseRuntimeElementCompositeDefinition<?> nextParameterDef =
099                                                        (BaseRuntimeElementCompositeDefinition<?>) theCtx.getElementDefinition(param.getClass());
100                                        BaseRuntimeChildDefinition nameChild = nextParameterDef.getChildByName("name");
101                                        List<IBase> nameValues = nameChild.getAccessor().getValues(param);
102                                        Optional<? extends IPrimitiveType<?>> nameValue = nameValues.stream()
103                                                        .filter(t -> t instanceof IPrimitiveType<?>)
104                                                        .map(t -> ((IPrimitiveType<?>) t))
105                                                        .findFirst();
106                                        return nameValue.isPresent()
107                                                        && theParameterName.equals(nameValue.get().getValueAsString());
108                                })
109                                .collect(Collectors.toList());
110        }
111
112        public static Optional<IBase> getParameterPart(FhirContext theCtx, IBase theParameter, String theParameterName) {
113                BaseRuntimeElementCompositeDefinition<?> nextParameterDef =
114                                (BaseRuntimeElementCompositeDefinition<?>) theCtx.getElementDefinition(theParameter.getClass());
115                BaseRuntimeChildDefinition valueChild = nextParameterDef.getChildByName("part");
116                List<IBase> parts = valueChild.getAccessor().getValues(theParameter);
117
118                for (IBase nextPart : parts) {
119                        Optional<IPrimitiveType> name = theCtx.newTerser().getSingleValue(nextPart, "name", IPrimitiveType.class);
120                        if (name.isPresent() && theParameterName.equals(name.get().getValueAsString())) {
121                                return Optional.of(nextPart);
122                        }
123                }
124
125                return Optional.empty();
126        }
127
128        public static Optional<IBase> getParameterPartValue(
129                        FhirContext theCtx, IBase theParameter, String theParameterName) {
130                Optional<IBase> part = getParameterPart(theCtx, theParameter, theParameterName);
131                if (part.isPresent()) {
132                        return theCtx.newTerser().getSingleValue(part.get(), "value[x]", IBase.class);
133                } else {
134                        return Optional.empty();
135                }
136        }
137
138        public static String getParameterPartValueAsString(
139                        FhirContext theCtx, IBase theParameter, String theParameterName) {
140                return getParameterPartValue(theCtx, theParameter, theParameterName)
141                                .map(t -> (IPrimitiveType<?>) t)
142                                .map(t -> t.getValueAsString())
143                                .orElse(null);
144        }
145
146        public static Optional<Integer> getParameterPartValueAsInteger(
147                        FhirContext theCtx, IBase theParameter, String theParameterName) {
148                return getParameterPartValue(theCtx, theParameter, theParameterName)
149                                .filter(t -> IPrimitiveType.class.isAssignableFrom(t.getClass()))
150                                .map(t -> (IPrimitiveType<?>) t)
151                                .map(IPrimitiveType::getValue)
152                                .filter(t -> Integer.class.isAssignableFrom(t.getClass()))
153                                .map(t -> (Integer) t);
154        }
155
156        private static <T> List<T> extractNamedParameters(
157                        FhirContext theCtx,
158                        IBaseParameters theParameters,
159                        String theParameterName,
160                        Function<IPrimitiveType<?>, T> theMapper) {
161                List<T> retVal = new ArrayList<>();
162
163                List<IBase> namedParameters = getNamedParameters(theCtx, theParameters, theParameterName);
164                for (IBase nextParameter : namedParameters) {
165                        BaseRuntimeElementCompositeDefinition<?> nextParameterDef =
166                                        (BaseRuntimeElementCompositeDefinition<?>) theCtx.getElementDefinition(nextParameter.getClass());
167                        BaseRuntimeChildDefinition valueChild = nextParameterDef.getChildByName("value[x]");
168                        List<IBase> valueValues = valueChild.getAccessor().getValues(nextParameter);
169                        valueValues.stream()
170                                        .filter(t -> t instanceof IPrimitiveType<?>)
171                                        .map(t -> ((IPrimitiveType<?>) t))
172                                        .map(theMapper)
173                                        .filter(t -> t != null)
174                                        .forEach(retVal::add);
175                }
176                return retVal;
177        }
178
179        private static void addClientParameter(
180                        FhirContext theContext,
181                        Object theValue,
182                        IBaseResource theTargetResource,
183                        BaseRuntimeChildDefinition paramChild,
184                        BaseRuntimeElementCompositeDefinition<?> paramChildElem,
185                        String theName) {
186                Validate.notNull(theValue, "theValue must not be null");
187
188                if (theValue instanceof IBaseResource) {
189                        IBase parameter =
190                                        createParameterRepetition(theContext, theTargetResource, paramChild, paramChildElem, theName);
191                        paramChildElem.getChildByName("resource").getMutator().addValue(parameter, (IBaseResource) theValue);
192                } else if (theValue instanceof IBaseDatatype) {
193                        IBase parameter =
194                                        createParameterRepetition(theContext, theTargetResource, paramChild, paramChildElem, theName);
195                        paramChildElem.getChildByName("value[x]").getMutator().addValue(parameter, (IBaseDatatype) theValue);
196                } else if (theValue instanceof Collection) {
197                        Collection<?> collection = (Collection<?>) theValue;
198                        for (Object next : collection) {
199                                addClientParameter(theContext, next, theTargetResource, paramChild, paramChildElem, theName);
200                        }
201                } else {
202                        throw new IllegalArgumentException(Msg.code(1806) + "Don't know how to handle value of type "
203                                        + theValue.getClass() + " for parameter " + theName);
204                }
205        }
206
207        /**
208         * Add a parameter value to a Parameters resource
209         *
210         * @param theContext    The FhirContext
211         * @param theParameters The Parameters resource
212         * @param theName       The parametr name
213         * @param theValue      The parameter value (can be a {@link IBaseResource resource} or a {@link IBaseDatatype datatype})
214         */
215        public static void addParameterToParameters(
216                        FhirContext theContext, IBaseParameters theParameters, String theName, Object theValue) {
217                RuntimeResourceDefinition def = theContext.getResourceDefinition(theParameters);
218                BaseRuntimeChildDefinition paramChild = def.getChildByName("parameter");
219                BaseRuntimeElementCompositeDefinition<?> paramChildElem =
220                                (BaseRuntimeElementCompositeDefinition<?>) paramChild.getChildByName("parameter");
221
222                addClientParameter(theContext, theValue, theParameters, paramChild, paramChildElem, theName);
223        }
224
225        /**
226         * Add a parameter value to a Parameters resource
227         *
228         * @param theContext           The FhirContext
229         * @param theParameters        The Parameters resource
230         * @param theName              The parameter name
231         * @param thePrimitiveDatatype The datatype, e.g. "string", or "uri"
232         * @param theValue             The value
233         */
234        public static void addParameterToParameters(
235                        FhirContext theContext,
236                        IBaseParameters theParameters,
237                        String theName,
238                        String thePrimitiveDatatype,
239                        String theValue) {
240                Validate.notBlank(thePrimitiveDatatype, "thePrimitiveDatatype must not be null or empty");
241
242                BaseRuntimeElementDefinition<?> datatypeDef = theContext.getElementDefinition(thePrimitiveDatatype);
243                IPrimitiveType<?> value = (IPrimitiveType<?>) datatypeDef.newInstance();
244                value.setValueAsString(theValue);
245
246                addParameterToParameters(theContext, theParameters, theName, value);
247        }
248
249        private static IBase createParameterRepetition(
250                        FhirContext theContext,
251                        IBaseResource theTargetResource,
252                        BaseRuntimeChildDefinition paramChild,
253                        BaseRuntimeElementCompositeDefinition<?> paramChildElem,
254                        String theName) {
255                IBase parameter = paramChildElem.newInstance();
256                paramChild.getMutator().addValue(theTargetResource, parameter);
257                IPrimitiveType<?> value;
258                value = createString(theContext, theName);
259                paramChildElem.getChildByName("name").getMutator().addValue(parameter, value);
260                return parameter;
261        }
262
263        public static IPrimitiveType<?> createString(FhirContext theContext, String theValue) {
264                IPrimitiveType<?> value;
265                if (theContext.getVersion().getVersion().isRi()) {
266                        value = (IPrimitiveType<?>)
267                                        theContext.getElementDefinition("string").newInstance(theValue);
268                } else {
269                        value = new StringDt(theValue);
270                }
271                return value;
272        }
273
274        public static IPrimitiveType<?> createUri(FhirContext theContext, String theValue) {
275                IPrimitiveType<?> value =
276                                (IPrimitiveType<?>) theContext.getElementDefinition("uri").newInstance(theValue);
277                return value;
278        }
279
280        public static IPrimitiveType<?> createCode(FhirContext theContext, String theValue) {
281                IPrimitiveType<?> value =
282                                (IPrimitiveType<?>) theContext.getElementDefinition("code").newInstance(theValue);
283                return value;
284        }
285
286        public static IBaseParameters newInstance(FhirContext theContext) {
287                Validate.notNull(theContext, "theContext must not be null");
288                return (IBaseParameters) theContext.getResourceDefinition("Parameters").newInstance();
289        }
290
291        @SuppressWarnings("unchecked")
292        public static void addParameterToParametersBoolean(
293                        FhirContext theCtx, IBaseParameters theParameters, String theName, boolean theValue) {
294                addParameterToParameters(theCtx, theParameters, theName, theCtx.getPrimitiveBoolean(theValue));
295        }
296
297        @SuppressWarnings("unchecked")
298        public static void addParameterToParametersCode(
299                        FhirContext theCtx, IBaseParameters theParameters, String theName, String theValue) {
300                IPrimitiveType<String> value =
301                                (IPrimitiveType<String>) theCtx.getElementDefinition("code").newInstance();
302                value.setValue(theValue);
303                addParameterToParameters(theCtx, theParameters, theName, value);
304        }
305
306        @SuppressWarnings("unchecked")
307        public static void addParameterToParametersInteger(
308                        FhirContext theCtx, IBaseParameters theParameters, String theName, int theValue) {
309                IPrimitiveType<Integer> count =
310                                (IPrimitiveType<Integer>) theCtx.getElementDefinition("integer").newInstance();
311                count.setValue(theValue);
312                addParameterToParameters(theCtx, theParameters, theName, count);
313        }
314
315        public static void addParameterToParametersLong(
316                        FhirContext theCtx, IBaseParameters theParameters, String theName, long theValue) {
317                addParameterToParametersDecimal(theCtx, theParameters, theName, BigDecimal.valueOf(theValue));
318        }
319
320        public static void addParameterToParametersDecimal(
321                        FhirContext theCtx, IBaseParameters theParameters, String theName, BigDecimal theValue) {
322                IPrimitiveType<BigDecimal> count = (IPrimitiveType<BigDecimal>)
323                                theCtx.getElementDefinition("decimal").newInstance();
324                count.setValue(theValue);
325                addParameterToParameters(theCtx, theParameters, theName, count);
326        }
327
328        public static void addParameterToParametersReference(
329                        FhirContext theCtx, IBaseParameters theParameters, String theName, String theReference) {
330                IBaseReference target =
331                                (IBaseReference) theCtx.getElementDefinition("reference").newInstance();
332                target.setReference(theReference);
333                addParameterToParameters(theCtx, theParameters, theName, target);
334        }
335
336        @SuppressWarnings("unchecked")
337        public static void addParameterToParametersString(
338                        FhirContext theCtx, IBaseParameters theParameters, String theName, String theValue) {
339                IPrimitiveType<String> value =
340                                (IPrimitiveType<String>) theCtx.getElementDefinition("string").newInstance();
341                value.setValue(theValue);
342                addParameterToParameters(theCtx, theParameters, theName, value);
343        }
344
345        @SuppressWarnings("unchecked")
346        public static void addParameterToParametersUri(
347                        FhirContext theCtx, IBaseParameters theParameters, String theName, String theValue) {
348                IPrimitiveType<String> value =
349                                (IPrimitiveType<String>) theCtx.getElementDefinition("uri").newInstance();
350                value.setValue(theValue);
351                addParameterToParameters(theCtx, theParameters, theName, value);
352        }
353
354        /**
355         * Add a parameter with no value (typically because we'll be adding sub-parameters)
356         */
357        public static IBase addParameterToParameters(
358                        FhirContext theContext, IBaseParameters theParameters, String theName) {
359                RuntimeResourceDefinition def = theContext.getResourceDefinition(theParameters);
360                BaseRuntimeChildDefinition paramChild = def.getChildByName("parameter");
361                BaseRuntimeElementCompositeDefinition<?> paramChildElem =
362                                (BaseRuntimeElementCompositeDefinition<?>) paramChild.getChildByName("parameter");
363
364                return createParameterRepetition(theContext, theParameters, paramChild, paramChildElem, theName);
365        }
366
367        public static void addPartCode(FhirContext theContext, IBase theParameter, String theName, String theCode) {
368                IPrimitiveType<String> value =
369                                (IPrimitiveType<String>) theContext.getElementDefinition("code").newInstance();
370                value.setValue(theCode);
371
372                addPart(theContext, theParameter, theName, value);
373        }
374
375        public static void addPartInteger(FhirContext theContext, IBase theParameter, String theName, Integer theInteger) {
376                IPrimitiveType<Integer> value = (IPrimitiveType<Integer>)
377                                theContext.getElementDefinition("integer").newInstance();
378                value.setValue(theInteger);
379
380                addPart(theContext, theParameter, theName, value);
381        }
382
383        public static void addPartString(FhirContext theContext, IBase theParameter, String theName, String theValue) {
384                IPrimitiveType<String> value = (IPrimitiveType<String>)
385                                theContext.getElementDefinition("string").newInstance();
386                value.setValue(theValue);
387
388                addPart(theContext, theParameter, theName, value);
389        }
390
391        public static void addPartUrl(FhirContext theContext, IBase theParameter, String theName, String theCode) {
392                IPrimitiveType<String> value =
393                                (IPrimitiveType<String>) theContext.getElementDefinition("url").newInstance();
394                value.setValue(theCode);
395
396                addPart(theContext, theParameter, theName, value);
397        }
398
399        public static void addPartBoolean(FhirContext theContext, IBase theParameter, String theName, Boolean theValue) {
400                addPart(theContext, theParameter, theName, theContext.getPrimitiveBoolean(theValue));
401        }
402
403        public static void addPartDecimal(FhirContext theContext, IBase theParameter, String theName, Double theValue) {
404                IPrimitiveType<BigDecimal> value = (IPrimitiveType<BigDecimal>)
405                                theContext.getElementDefinition("decimal").newInstance();
406                if (theValue == null) {
407                        value.setValue(null);
408                } else {
409                        BigDecimal decimalValue = BigDecimal.valueOf(theValue);
410                        if (decimalValue.scale() < 0) {
411                                decimalValue = decimalValue.setScale(0);
412                        }
413                        value.setValue(decimalValue);
414                }
415                addPart(theContext, theParameter, theName, value);
416        }
417
418        public static void addPartCoding(
419                        FhirContext theContext,
420                        IBase theParameter,
421                        String theName,
422                        String theSystem,
423                        String theCode,
424                        String theDisplay) {
425                IBase coding = theContext.getElementDefinition("coding").newInstance();
426
427                BaseRuntimeElementCompositeDefinition<?> codingDef =
428                                (BaseRuntimeElementCompositeDefinition<?>) theContext.getElementDefinition(coding.getClass());
429                codingDef.getChildByName("system").getMutator().addValue(coding, createUri(theContext, theSystem));
430                codingDef.getChildByName("code").getMutator().addValue(coding, createCode(theContext, theCode));
431                codingDef.getChildByName("display").getMutator().addValue(coding, createString(theContext, theDisplay));
432
433                addPart(theContext, theParameter, theName, coding);
434        }
435
436        public static void addPart(FhirContext theContext, IBase theParameter, String theName, IBase theValue) {
437                BaseRuntimeElementCompositeDefinition<?> def =
438                                (BaseRuntimeElementCompositeDefinition<?>) theContext.getElementDefinition(theParameter.getClass());
439                BaseRuntimeChildDefinition partChild = def.getChildByName("part");
440
441                BaseRuntimeElementCompositeDefinition<?> partChildElem =
442                                (BaseRuntimeElementCompositeDefinition<?>) partChild.getChildByName("part");
443                IBase part = partChildElem.newInstance();
444                partChild.getMutator().addValue(theParameter, part);
445
446                IPrimitiveType<String> name = (IPrimitiveType<String>)
447                                theContext.getElementDefinition("string").newInstance();
448                name.setValue(theName);
449                partChildElem.getChildByName("name").getMutator().addValue(part, name);
450
451                if (theValue instanceof IBaseResource) {
452                        partChildElem.getChildByName("resource").getMutator().addValue(part, theValue);
453                } else {
454                        partChildElem.getChildByName("value[x]").getMutator().addValue(part, theValue);
455                }
456        }
457
458        public static void addPartResource(
459                        FhirContext theContext, IBase theParameter, String theName, IBaseResource theValue) {
460                BaseRuntimeElementCompositeDefinition<?> def =
461                                (BaseRuntimeElementCompositeDefinition<?>) theContext.getElementDefinition(theParameter.getClass());
462                BaseRuntimeChildDefinition partChild = def.getChildByName("part");
463
464                BaseRuntimeElementCompositeDefinition<?> partChildElem =
465                                (BaseRuntimeElementCompositeDefinition<?>) partChild.getChildByName("part");
466                IBase part = partChildElem.newInstance();
467                partChild.getMutator().addValue(theParameter, part);
468
469                IPrimitiveType<String> name = (IPrimitiveType<String>)
470                                theContext.getElementDefinition("string").newInstance();
471                name.setValue(theName);
472                partChildElem.getChildByName("name").getMutator().addValue(part, name);
473
474                partChildElem.getChildByName("resource").getMutator().addValue(part, theValue);
475        }
476
477        public static List<String> getNamedParameterPartAsString(
478                        FhirContext theCtx, IBaseParameters theParameters, String thePartName, String theParameterName) {
479                return extractNamedParameterPartsAsString(theCtx, theParameters, thePartName, theParameterName);
480        }
481
482        // TODO KHS need to consolidate duplicated functionality that came in from different branches
483        private static List<String> extractNamedParameterPartsAsString(
484                        FhirContext theCtx, IBaseParameters theParameters, String thePartName, String theParameterName) {
485                List<IBase> parameterReps = getParameterReps(theCtx, theParameters);
486
487                List<String> retVal = new ArrayList<>();
488
489                for (IBase nextParameter : parameterReps) {
490                        BaseRuntimeElementCompositeDefinition<?> nextParameterDef =
491                                        (BaseRuntimeElementCompositeDefinition<?>) theCtx.getElementDefinition(nextParameter.getClass());
492                        Optional<? extends IPrimitiveType<?>> nameValue = getNameValue(nextParameter, nextParameterDef);
493                        if (!nameValue.isPresent() || !thePartName.equals(nameValue.get().getValueAsString())) {
494                                continue;
495                        }
496
497                        BaseRuntimeChildDefinition partChild = nextParameterDef.getChildByName("part");
498                        List<IBase> partValues = partChild.getAccessor().getValues(nextParameter);
499                        for (IBase partValue : partValues) {
500                                BaseRuntimeElementCompositeDefinition<?> partParameterDef =
501                                                (BaseRuntimeElementCompositeDefinition<?>) theCtx.getElementDefinition(partValue.getClass());
502                                Optional<? extends IPrimitiveType<?>> partNameValue = getNameValue(partValue, partParameterDef);
503                                if (!partNameValue.isPresent()
504                                                || !theParameterName.equals(partNameValue.get().getValueAsString())) {
505                                        continue;
506                                }
507                                BaseRuntimeChildDefinition valueChild = partParameterDef.getChildByName("value[x]");
508                                List<IBase> valueValues = valueChild.getAccessor().getValues(partValue);
509                                valueValues.stream()
510                                                .filter(t -> t instanceof IPrimitiveType<?>)
511                                                .map(t -> ((IPrimitiveType<String>) t))
512                                                .map(t -> defaultIfBlank(t.getValueAsString(), null))
513                                                .filter(t -> t != null)
514                                                .forEach(retVal::add);
515                        }
516                }
517                return retVal;
518        }
519
520        private static List<IBase> getParameterReps(FhirContext theCtx, IBaseParameters theParameters) {
521                Validate.notNull(theParameters, "theParameters must not be null");
522                RuntimeResourceDefinition resDef = theCtx.getResourceDefinition(theParameters.getClass());
523                BaseRuntimeChildDefinition parameterChild = resDef.getChildByName("parameter");
524                return parameterChild.getAccessor().getValues(theParameters);
525        }
526
527        private static Optional<? extends IPrimitiveType<?>> getNameValue(
528                        IBase nextParameter, BaseRuntimeElementCompositeDefinition<?> theNextParameterDef) {
529                BaseRuntimeChildDefinition nameChild = theNextParameterDef.getChildByName("name");
530                List<IBase> nameValues = nameChild.getAccessor().getValues(nextParameter);
531                return nameValues.stream()
532                                .filter(t -> t instanceof IPrimitiveType<?>)
533                                .map(t -> ((IPrimitiveType<?>) t))
534                                .findFirst();
535        }
536
537        @Nullable
538        public static String extractDescription(AnnotatedElement theType) {
539                Description description = theType.getAnnotation(Description.class);
540                if (description != null) {
541                        return extractDescription(description);
542                } else {
543                        return null;
544                }
545        }
546
547        @Nullable
548        public static String extractDescription(Description desc) {
549                String description = desc.value();
550                if (isBlank(description)) {
551                        description = desc.formalDefinition();
552                }
553                if (isBlank(description)) {
554                        description = desc.shortDefinition();
555                }
556                return defaultIfBlank(description, null);
557        }
558
559        @Nullable
560        public static String extractShortDefinition(AnnotatedElement theType) {
561                Description description = theType.getAnnotation(Description.class);
562                if (description != null) {
563                        return defaultIfBlank(description.shortDefinition(), null);
564                } else {
565                        return null;
566                }
567        }
568
569        public static String extractDescription(Annotation[] theParameterAnnotations) {
570                for (Annotation next : theParameterAnnotations) {
571                        if (next instanceof Description) {
572                                return extractDescription((Description) next);
573                        }
574                }
575                return null;
576        }
577
578        public static List<String> extractExamples(Annotation[] theParameterAnnotations) {
579                ArrayList<String> retVal = null;
580                for (Annotation next : theParameterAnnotations) {
581                        if (next instanceof Description) {
582                                String[] examples = ((Description) next).example();
583                                if (examples.length > 0) {
584                                        if (retVal == null) {
585                                                retVal = new ArrayList<>();
586                                        }
587                                        retVal.addAll(Arrays.asList(examples));
588                                }
589                        }
590                }
591                return retVal;
592        }
593}