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.i18n.Msg; 023import ca.uhn.fhir.model.api.annotation.DatatypeDef; 024import ca.uhn.fhir.model.api.annotation.ResourceDef; 025import org.hl7.fhir.instance.model.api.IBase; 026import org.hl7.fhir.instance.model.api.IBaseDatatype; 027import org.hl7.fhir.instance.model.api.IPrimitiveType; 028 029import java.lang.reflect.ParameterizedType; 030import java.lang.reflect.Type; 031import java.util.ArrayList; 032import java.util.Collections; 033import java.util.List; 034import java.util.Map; 035 036import static org.apache.commons.lang3.StringUtils.isBlank; 037 038public class RuntimePrimitiveDatatypeDefinition extends BaseRuntimeElementDefinition<IPrimitiveType<?>> 039 implements IRuntimeDatatypeDefinition { 040 041 private Class<?> myNativeType; 042 private BaseRuntimeElementDefinition<?> myProfileOf; 043 private Class<? extends IBaseDatatype> myProfileOfType; 044 private boolean mySpecialization; 045 private List<BaseRuntimeChildDefinition> myChildren; 046 private RuntimeChildExt myRuntimeChildExt; 047 048 public RuntimePrimitiveDatatypeDefinition( 049 DatatypeDef theDef, Class<? extends IPrimitiveType<?>> theImplementingClass, boolean theStandardType) { 050 super(theDef.name(), theImplementingClass, theStandardType); 051 052 String resourceName = theDef.name(); 053 if (isBlank(resourceName)) { 054 throw new ConfigurationException(Msg.code(1689) + "Resource type @" + ResourceDef.class.getSimpleName() 055 + " annotation contains no resource name: " + theImplementingClass.getCanonicalName()); 056 } 057 058 mySpecialization = theDef.isSpecialization(); 059 myProfileOfType = theDef.profileOf(); 060 if (myProfileOfType.equals(IBaseDatatype.class)) { 061 myProfileOfType = null; 062 } 063 064 determineNativeType(theImplementingClass); 065 } 066 067 @Override 068 public List<BaseRuntimeChildDefinition> getChildren() { 069 return myChildren; 070 } 071 072 @Override 073 public BaseRuntimeChildDefinition getChildByName(String theChildName) { 074 if ("extension".equals(theChildName)) { 075 return myRuntimeChildExt; 076 } 077 return null; 078 } 079 080 private void determineNativeType(Class<? extends IPrimitiveType<?>> theImplementingClass) { 081 Class<?> clazz = theImplementingClass; 082 while (clazz.equals(Object.class) == false) { 083 Type type = clazz.getGenericSuperclass(); 084 if (type instanceof ParameterizedType) { 085 ParameterizedType superPt = (ParameterizedType) type; 086 Type rawType = superPt.getRawType(); 087 if (rawType instanceof Class) { 088 Class<?> rawClass = (Class<?>) rawType; 089 if (rawClass.getName().endsWith(".BasePrimitive") 090 || rawClass.getName().endsWith(".PrimitiveType")) { 091 Type typeVariable = superPt.getActualTypeArguments()[0]; 092 if (typeVariable instanceof Class) { 093 myNativeType = (Class<?>) typeVariable; 094 break; 095 } 096 } 097 } 098 } 099 clazz = clazz.getSuperclass(); 100 } 101 } 102 103 @Override 104 public ca.uhn.fhir.context.BaseRuntimeElementDefinition.ChildTypeEnum getChildType() { 105 return ChildTypeEnum.PRIMITIVE_DATATYPE; 106 } 107 108 public Class<?> getNativeType() { 109 return myNativeType; 110 } 111 112 @Override 113 public Class<? extends IBaseDatatype> getProfileOf() { 114 return myProfileOfType; 115 } 116 117 @Override 118 public boolean isProfileOf(Class<? extends IBaseDatatype> theType) { 119 if (myProfileOfType != null) { 120 if (myProfileOfType.equals(theType)) { 121 return true; 122 } else if (myProfileOf instanceof IRuntimeDatatypeDefinition) { 123 return ((IRuntimeDatatypeDefinition) myProfileOf).isProfileOf(theType); 124 } 125 } 126 return false; 127 } 128 129 @Override 130 public boolean isSpecialization() { 131 return mySpecialization; 132 } 133 134 @Override 135 void sealAndInitialize( 136 FhirContext theContext, 137 Map<Class<? extends IBase>, BaseRuntimeElementDefinition<?>> theClassToElementDefinitions) { 138 super.sealAndInitialize(theContext, theClassToElementDefinitions); 139 140 if (myProfileOfType != null) { 141 myProfileOf = theClassToElementDefinitions.get(myProfileOfType); 142 if (myProfileOf == null) { 143 StringBuilder b = new StringBuilder(); 144 b.append("Unknown profileOf value: "); 145 b.append(myProfileOfType); 146 b.append(" in type "); 147 b.append(getImplementingClass().getName()); 148 b.append(" - Valid types: "); 149 b.append(theClassToElementDefinitions.keySet()); 150 throw new ConfigurationException(Msg.code(1690) + b.toString()); 151 } 152 } 153 154 myRuntimeChildExt = new RuntimeChildExt(); 155 myRuntimeChildExt.sealAndInitialize(theContext, theClassToElementDefinitions); 156 157 myChildren = new ArrayList<>(); 158 myChildren.addAll(super.getChildren()); 159 myChildren.add(myRuntimeChildExt); 160 myChildren = Collections.unmodifiableList(myChildren); 161 } 162}