001/*- 002 * #%L 003 * HAPI FHIR JPA Server 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.jpa.dao; 021 022import ca.uhn.fhir.i18n.Msg; 023import ca.uhn.fhir.model.primitive.BooleanDt; 024import org.apache.commons.lang3.reflect.FieldUtils; 025import org.hl7.fhir.instance.model.api.IBaseBooleanDatatype; 026import org.hl7.fhir.instance.model.api.IBaseCoding; 027 028import java.lang.reflect.Field; 029import java.util.Map; 030import java.util.concurrent.ConcurrentHashMap; 031 032/** 033 * We are trying to preserve null behaviour despite IBaseCoding using primitive boolean for userSelected. 034 */ 035public class CodingSpy { 036 final Map<Class, Field> mySpies = new ConcurrentHashMap<>(); 037 038 /** 039 * Reach into the Coding and pull out the Boolean instead of the boolean. 040 * @param theValue the Coding, or CodingDt 041 * @return the Boolean 042 */ 043 public Boolean getBooleanObject(IBaseCoding theValue) { 044 Field spy = getSpy(theValue); 045 try { 046 Object o = spy.get(theValue); 047 if (o == null) { 048 return null; 049 } 050 if (o instanceof BooleanDt) { 051 BooleanDt booleanDt = (BooleanDt) o; 052 return booleanDt.getValue(); 053 } 054 if (o instanceof IBaseBooleanDatatype) { 055 IBaseBooleanDatatype booleanValue = (IBaseBooleanDatatype) o; 056 return booleanValue.getValue(); 057 } 058 if (o instanceof Boolean) { 059 return (Boolean) o; 060 } 061 throw new RuntimeException( 062 Msg.code(2342) + "unsupported type :" + theValue.getClass().getName()); 063 } catch (IllegalAccessException theException) { 064 // should never happen - all Coding models have this field. 065 throw new RuntimeException(Msg.code(2343) + "illegal access during reflection", theException); 066 } 067 } 068 069 private Field getSpy(IBaseCoding theValue) { 070 return mySpies.computeIfAbsent(theValue.getClass(), k -> getFieldHandle(k)); 071 } 072 073 private static Field getFieldHandle(Class k) { 074 Field result = FieldUtils.getField(k, "userSelected", true); 075 if (result == null) { 076 result = FieldUtils.getField(k, "myUserSelected", true); 077 } 078 return result; 079 } 080}