Add a test

This commit is contained in:
James Agnew 2019-10-15 07:34:44 -04:00
parent 2725797610
commit ff4fba15c9
2 changed files with 167 additions and 38 deletions

View File

@ -29,6 +29,7 @@ import ca.uhn.fhir.rest.api.RestSearchParameterTypeEnum;
import ca.uhn.fhir.util.ReflectionUtil;
import org.hl7.fhir.instance.model.api.*;
import javax.annotation.Nonnull;
import java.io.IOException;
import java.io.InputStream;
import java.lang.annotation.Annotation;
@ -44,56 +45,47 @@ import static org.apache.commons.lang3.StringUtils.isBlank;
class ModelScanner {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ModelScanner.class);
private Map<Class<? extends IBase>, BaseRuntimeElementDefinition<?>> myClassToElementDefinitions = new HashMap<Class<? extends IBase>, BaseRuntimeElementDefinition<?>>();
private Map<Class<? extends IBase>, BaseRuntimeElementDefinition<?>> myClassToElementDefinitions = new HashMap<>();
private FhirContext myContext;
private Map<String, RuntimeResourceDefinition> myIdToResourceDefinition = new HashMap<String, RuntimeResourceDefinition>();
private Map<String, BaseRuntimeElementDefinition<?>> myNameToElementDefinitions = new HashMap<String, BaseRuntimeElementDefinition<?>>();
private Map<String, RuntimeResourceDefinition> myNameToResourceDefinitions = new HashMap<String, RuntimeResourceDefinition>();
private Map<String, Class<? extends IBaseResource>> myNameToResourceType = new HashMap<String, Class<? extends IBaseResource>>();
private Map<String, RuntimeResourceDefinition> myIdToResourceDefinition = new HashMap<>();
private Map<String, BaseRuntimeElementDefinition<?>> myNameToElementDefinitions = new HashMap<>();
private Map<String, RuntimeResourceDefinition> myNameToResourceDefinitions = new HashMap<>();
private Map<String, Class<? extends IBaseResource>> myNameToResourceType = new HashMap<>();
private RuntimeChildUndeclaredExtensionDefinition myRuntimeChildUndeclaredExtensionDefinition;
private Set<Class<? extends IBase>> myScanAlso = new HashSet<Class<? extends IBase>>();
private Set<Class<? extends IBase>> myScanAlso = new HashSet<>();
private FhirVersionEnum myVersion;
private Set<Class<? extends IBase>> myVersionTypes;
ModelScanner(FhirContext theContext, FhirVersionEnum theVersion, Map<Class<? extends IBase>, BaseRuntimeElementDefinition<?>> theExistingDefinitions,
Collection<Class<? extends IBase>> theResourceTypes) throws ConfigurationException {
@Nonnull Collection<Class<? extends IBase>> theResourceTypes) throws ConfigurationException {
myContext = theContext;
myVersion = theVersion;
Set<Class<? extends IBase>> toScan;
if (theResourceTypes != null) {
toScan = new HashSet<Class<? extends IBase>>(theResourceTypes);
} else {
toScan = new HashSet<Class<? extends IBase>>();
}
Set<Class<? extends IBase>> toScan = new HashSet<>(theResourceTypes);
init(theExistingDefinitions, toScan);
}
public Map<Class<? extends IBase>, BaseRuntimeElementDefinition<?>> getClassToElementDefinitions() {
Map<Class<? extends IBase>, BaseRuntimeElementDefinition<?>> getClassToElementDefinitions() {
return myClassToElementDefinitions;
}
public Map<String, RuntimeResourceDefinition> getIdToResourceDefinition() {
Map<String, RuntimeResourceDefinition> getIdToResourceDefinition() {
return myIdToResourceDefinition;
}
public Map<String, BaseRuntimeElementDefinition<?>> getNameToElementDefinitions() {
Map<String, BaseRuntimeElementDefinition<?>> getNameToElementDefinitions() {
return myNameToElementDefinitions;
}
public Map<String, RuntimeResourceDefinition> getNameToResourceDefinition() {
Map<String, RuntimeResourceDefinition> getNameToResourceDefinition() {
return myNameToResourceDefinitions;
}
public Map<String, RuntimeResourceDefinition> getNameToResourceDefinitions() {
return (myNameToResourceDefinitions);
}
public Map<String, Class<? extends IBaseResource>> getNameToResourceType() {
Map<String, Class<? extends IBaseResource>> getNameToResourceType() {
return myNameToResourceType;
}
public RuntimeChildUndeclaredExtensionDefinition getRuntimeChildUndeclaredExtensionDefinition() {
RuntimeChildUndeclaredExtensionDefinition getRuntimeChildUndeclaredExtensionDefinition() {
return myRuntimeChildUndeclaredExtensionDefinition;
}
@ -145,11 +137,10 @@ class ModelScanner {
}
private boolean isStandardType(Class<? extends IBase> theClass) {
boolean retVal = myVersionTypes.contains(theClass);
return retVal;
return myVersionTypes.contains(theClass);
}
private void scan(Class<? extends IBase> theClass) throws ConfigurationException {
void scan(Class<? extends IBase> theClass) throws ConfigurationException {
BaseRuntimeElementDefinition<?> existingDef = myClassToElementDefinitions.get(theClass);
if (existingDef != null) {
return;
@ -204,9 +195,6 @@ class ModelScanner {
ourLog.debug("Scanning resource block class: {}", theClass.getName());
String resourceName = theClass.getCanonicalName();
if (isBlank(resourceName)) {
throw new ConfigurationException("Block type @" + Block.class.getSimpleName() + " annotation contains no name: " + theClass.getCanonicalName());
}
// Just in case someone messes up when upgrading from DSTU2
if (myContext.getVersion().getVersion().isEqualOrNewerThan(FhirVersionEnum.DSTU3)) {
@ -341,14 +329,14 @@ class ModelScanner {
private void scanResourceForSearchParams(Class<? extends IBaseResource> theClass, RuntimeResourceDefinition theResourceDef) {
Map<String, RuntimeSearchParam> nameToParam = new HashMap<String, RuntimeSearchParam>();
Map<Field, SearchParamDefinition> compositeFields = new LinkedHashMap<Field, SearchParamDefinition>();
Map<String, RuntimeSearchParam> nameToParam = new HashMap<>();
Map<Field, SearchParamDefinition> compositeFields = new LinkedHashMap<>();
/*
* Make sure we pick up fields in interfaces too.. This ensures that we
* grab the _id field which generally gets picked up via interface
*/
Set<Field> fields = new HashSet<Field>(Arrays.asList(theClass.getFields()));
Set<Field> fields = new HashSet<>(Arrays.asList(theClass.getFields()));
Class<?> nextClass = theClass;
do {
for (Class<?> nextInterface : nextClass.getInterfaces()) {
@ -400,12 +388,12 @@ class ModelScanner {
for (Entry<Field, SearchParamDefinition> nextEntry : compositeFields.entrySet()) {
SearchParamDefinition searchParam = nextEntry.getValue();
List<RuntimeSearchParam> compositeOf = new ArrayList<RuntimeSearchParam>();
List<RuntimeSearchParam> compositeOf = new ArrayList<>();
for (String nextName : searchParam.compositeOf()) {
RuntimeSearchParam param = nameToParam.get(nextName);
if (param == null) {
ourLog.warn("Search parameter {}.{} declares that it is a composite with compositeOf value '{}' but that is not a valid parametr name itself. Valid values are: {}",
new Object[]{theResourceDef.getName(), searchParam.name(), nextName, nameToParam.keySet()});
theResourceDef.getName(), searchParam.name(), nextName, nameToParam.keySet());
continue;
}
compositeOf.add(param);
@ -417,7 +405,7 @@ class ModelScanner {
}
private Set<String> toTargetList(Class<? extends IBaseResource>[] theTarget) {
HashSet<String> retVal = new HashSet<String>();
HashSet<String> retVal = new HashSet<>();
for (Class<? extends IBaseResource> nextType : theTarget) {
ResourceDef resourceDef = nextType.getAnnotation(ResourceDef.class);
@ -486,7 +474,7 @@ class ModelScanner {
}
static Set<Class<? extends IBase>> scanVersionPropertyFile(Set<Class<? extends IBase>> theDatatypes, Map<String, Class<? extends IBaseResource>> theResourceTypes, FhirVersionEnum theVersion, Map<Class<? extends IBase>, BaseRuntimeElementDefinition<?>> theExistingElementDefinitions) {
Set<Class<? extends IBase>> retVal = new HashSet<Class<? extends IBase>>();
Set<Class<? extends IBase>> retVal = new HashSet<>();
try (InputStream str = theVersion.getVersionImplementation().getFhirVersionPropertiesFile()) {
Properties prop = new Properties();

View File

@ -1,17 +1,19 @@
package ca.uhn.fhir.context;
import ca.uhn.fhir.model.api.annotation.*;
import ca.uhn.fhir.model.api.annotation.Extension;
import ca.uhn.fhir.model.api.annotation.*;
import ca.uhn.fhir.model.primitive.StringDt;
import ca.uhn.fhir.parser.DataFormatException;
import ca.uhn.fhir.util.TestUtil;
import org.hl7.fhir.dstu3.model.*;
import org.hl7.fhir.instance.model.api.IBase;
import org.junit.AfterClass;
import org.junit.Ignore;
import org.junit.Test;
import java.util.List;
import java.util.*;
import static org.hamcrest.Matchers.contains;
import static org.junit.Assert.*;
public class ModelScannerDstu3Test {
@ -149,6 +151,73 @@ public class ModelScannerDstu3Test {
}
}
@Test
public void testScanDuplicate() {
FhirContext ctx = FhirContext.forDstu3();
FhirVersionEnum version = FhirVersionEnum.DSTU3;
Map<Class<? extends IBase>, BaseRuntimeElementDefinition<?>> definitions = new HashMap<>();
Collection<Class<? extends IBase>> resourceTypes = new ArrayList<>();
resourceTypes.add(Patient.class);
ModelScanner scanner = new ModelScanner(ctx, version, definitions, resourceTypes);
assertThat(resourceTypes, contains(Patient.class));
// Extra scans don't do anything
scanner.scan(Patient.class);
scanner.scan(Patient.class);
assertThat(resourceTypes, contains(Patient.class));
}
@Test
public void testScanInvalidResource() {
FhirContext ctx = FhirContext.forDstu3();
FhirVersionEnum version = FhirVersionEnum.DSTU3;
Map<Class<? extends IBase>, BaseRuntimeElementDefinition<?>> definitions = new HashMap<>();
Collection<Class<? extends IBase>> resourceTypes = new ArrayList<>();
ModelScanner scanner = new ModelScanner(ctx, version, definitions, resourceTypes);
try {
scanner.scan(BadPatient.class);
fail();
} catch (ConfigurationException e) {
assertEquals("Resource type contains a @ResourceDef annotation but does not implement ca.uhn.fhir.model.api.IResource: ca.uhn.fhir.context.ModelScannerDstu3Test.BadPatient", e.getMessage());
}
}
@Test
public void testScanInvalidType() {
FhirContext ctx = FhirContext.forDstu3();
FhirVersionEnum version = FhirVersionEnum.DSTU3;
Map<Class<? extends IBase>, BaseRuntimeElementDefinition<?>> definitions = new HashMap<>();
Collection<Class<? extends IBase>> resourceTypes = new ArrayList<>();
ModelScanner scanner = new ModelScanner(ctx, version, definitions, resourceTypes);
Class clazz = String.class;
try {
scanner.scan(clazz);
fail();
} catch (ConfigurationException e) {
assertEquals("Resource class[java.lang.String] does not contain any valid HAPI-FHIR annotations", e.getMessage());
}
}
@Test
public void testScanInvalidBlock() {
FhirContext ctx = FhirContext.forDstu3();
FhirVersionEnum version = FhirVersionEnum.DSTU3;
Map<Class<? extends IBase>, BaseRuntimeElementDefinition<?>> definitions = new HashMap<>();
Collection<Class<? extends IBase>> resourceTypes = new ArrayList<>();
ModelScanner scanner = new ModelScanner(ctx, version, definitions, resourceTypes);
try {
scanner.scan(BadPatient.BadBlock.class);
fail();
} catch (ConfigurationException e) {
assertEquals("Type contains a @Block annotation but does not implement ca.uhn.fhir.model.api.IResourceBlock: ca.uhn.fhir.context.ModelScannerDstu3Test.BadPatient.BadBlock", e.getMessage());
}
}
class NoResourceDef extends Patient {
@SearchParamDefinition(name = "foo", path = "Patient.telecom", type = "bar")
public static final String SP_TELECOM = "foo";
@ -156,6 +225,78 @@ public class ModelScannerDstu3Test {
}
@ResourceDef(name = "Patient")
public static class BadPatient implements IBase {
@Child(name = "badBlock")
private BadBlock myChild;
@Override
public boolean isEmpty() {
return false;
}
@Override
public boolean hasFormatComment() {
return false;
}
@Override
public List<String> getFormatCommentsPre() {
return null;
}
@Override
public List<String> getFormatCommentsPost() {
return null;
}
@Override
public Object getUserData(String theName) {
return null;
}
@Override
public void setUserData(String theName, Object theValue) {
}
@Block
public static class BadBlock implements IBase {
@Override
public boolean isEmpty() {
return false;
}
@Override
public boolean hasFormatComment() {
return false;
}
@Override
public List<String> getFormatCommentsPre() {
return null;
}
@Override
public List<String> getFormatCommentsPost() {
return null;
}
@Override
public Object getUserData(String theName) {
return null;
}
@Override
public void setUserData(String theName, Object theValue) {
}
}
}
@ResourceDef(name = "Patient")
public static class CompartmentForNonReferenceParam extends Patient {
@SearchParamDefinition(name = "foo", path = "Patient.telecom", type = "string", providesMembershipIn = {@Compartment(name = "Patient"), @Compartment(name = "Device")})