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.context; 021 022import ca.uhn.fhir.model.api.IDatatype; 023import ca.uhn.fhir.model.api.IResource; 024import ca.uhn.fhir.model.api.annotation.Child; 025import ca.uhn.fhir.model.api.annotation.Description; 026import ca.uhn.fhir.model.primitive.XhtmlDt; 027import org.hl7.fhir.instance.model.api.IBase; 028import org.hl7.fhir.instance.model.api.IBaseDatatype; 029import org.hl7.fhir.instance.model.api.IBaseReference; 030 031import java.lang.reflect.Field; 032import java.util.ArrayList; 033import java.util.Comparator; 034import java.util.List; 035import java.util.Map; 036 037public class RuntimeChildAny extends RuntimeChildChoiceDefinition { 038 039 public RuntimeChildAny( 040 Field theField, String theElementName, Child theChildAnnotation, Description theDescriptionAnnotation) { 041 super(theField, theElementName, theChildAnnotation, theDescriptionAnnotation); 042 } 043 044 @Override 045 void sealAndInitialize( 046 FhirContext theContext, 047 Map<Class<? extends IBase>, BaseRuntimeElementDefinition<?>> theClassToElementDefinitions) { 048 List<Class<? extends IBase>> choiceTypes = new ArrayList<>(); 049 List<Class<? extends IBase>> specializationChoiceTypes = new ArrayList<>(); 050 051 for (Class<? extends IBase> next : theClassToElementDefinitions.keySet()) { 052 if (next.equals(XhtmlDt.class)) { 053 continue; 054 } 055 056 boolean isSpecialization = false; 057 BaseRuntimeElementDefinition<?> nextDef = theClassToElementDefinitions.get(next); 058 if (nextDef instanceof IRuntimeDatatypeDefinition) { 059 if (((IRuntimeDatatypeDefinition) nextDef).isSpecialization()) { 060 /* 061 * Things like BoundCodeDt shoudn't be considered as valid options for an "any" choice, since 062 * we'll already have CodeDt as an option 063 */ 064 isSpecialization = true; 065 } 066 } 067 068 if (IResource.class.isAssignableFrom(next) 069 || IDatatype.class.isAssignableFrom(next) 070 || IBaseDatatype.class.isAssignableFrom(next) 071 || IBaseReference.class.isAssignableFrom(next)) { 072 if (isSpecialization) { 073 specializationChoiceTypes.add(next); 074 } else { 075 choiceTypes.add(next); 076 } 077 } 078 } 079 080 choiceTypes.sort(new ResourceTypeNameComparator()); 081 specializationChoiceTypes.sort(new ResourceTypeNameComparator()); 082 083 setChoiceTypes(choiceTypes, specializationChoiceTypes); 084 085 super.sealAndInitialize(theContext, theClassToElementDefinitions); 086 } 087 088 private static class ResourceTypeNameComparator implements Comparator<Class<?>> { 089 @Override 090 public int compare(Class<?> theO1, Class<?> theO2) { 091 boolean o1res = IResource.class.isAssignableFrom(theO1); 092 boolean o2res = IResource.class.isAssignableFrom(theO2); 093 if (o1res && o2res) { 094 return theO1.getSimpleName().compareTo(theO2.getSimpleName()); 095 } else if (o1res) { 096 return -1; 097 } else if (!o2res) { 098 return 0; 099 } else { 100 return 1; 101 } 102 } 103 } 104}