Start adding ability to override fields in extended definition classes
This commit is contained in:
parent
901ce12e8e
commit
d5c6623da0
|
@ -37,7 +37,8 @@ import ca.uhn.fhir.model.api.annotation.Description;
|
||||||
import ca.uhn.fhir.util.BeanUtils;
|
import ca.uhn.fhir.util.BeanUtils;
|
||||||
|
|
||||||
public abstract class BaseRuntimeDeclaredChildDefinition extends BaseRuntimeChildDefinition {
|
public abstract class BaseRuntimeDeclaredChildDefinition extends BaseRuntimeChildDefinition {
|
||||||
|
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BaseRuntimeDeclaredChildDefinition.class);
|
||||||
|
private Boolean ourUseMethodAccessors;
|
||||||
private final IAccessor myAccessor;
|
private final IAccessor myAccessor;
|
||||||
private final String myElementName;
|
private final String myElementName;
|
||||||
private final Field myField;
|
private final Field myField;
|
||||||
|
@ -76,6 +77,27 @@ public abstract class BaseRuntimeDeclaredChildDefinition extends BaseRuntimeChil
|
||||||
|
|
||||||
// TODO: handle lists (max>0), and maybe max=0?
|
// TODO: handle lists (max>0), and maybe max=0?
|
||||||
|
|
||||||
|
// TODO: finish implementing field level accessors/mutators
|
||||||
|
if (ourUseMethodAccessors == null) {
|
||||||
|
try {
|
||||||
|
myField.setAccessible(true);
|
||||||
|
ourUseMethodAccessors = true;
|
||||||
|
} catch (SecurityException e) {
|
||||||
|
ourLog.info("Can not use field accessors/mutators, going to use methods instead");
|
||||||
|
ourUseMethodAccessors = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ourUseMethodAccessors == false) {
|
||||||
|
if (List.class.equals(myField.getType())) {
|
||||||
|
// TODO: verify that generic type is IElement
|
||||||
|
myAccessor = new FieldListAccessor();
|
||||||
|
myMutator = new FieldListMutator();
|
||||||
|
} else {
|
||||||
|
myAccessor = new FieldPlainAccessor();
|
||||||
|
myMutator = new FieldPlainMutator();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
Class<?> declaringClass = myField.getDeclaringClass();
|
Class<?> declaringClass = myField.getDeclaringClass();
|
||||||
final Class<?> targetReturnType = myField.getType();
|
final Class<?> targetReturnType = myField.getType();
|
||||||
try {
|
try {
|
||||||
|
@ -103,6 +125,7 @@ public abstract class BaseRuntimeDeclaredChildDefinition extends BaseRuntimeChil
|
||||||
} catch (NoSuchFieldException e) {
|
} catch (NoSuchFieldException e) {
|
||||||
throw new ConfigurationException(e);
|
throw new ConfigurationException(e);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -160,6 +183,77 @@ public abstract class BaseRuntimeDeclaredChildDefinition extends BaseRuntimeChil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private final class FieldPlainMutator implements IMutator {
|
||||||
|
@Override
|
||||||
|
public void addValue(Object theTarget, IElement theValue) {
|
||||||
|
try {
|
||||||
|
myField.set(theTarget, theValue);
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
throw new ConfigurationException("Failed to set value", e);
|
||||||
|
} catch (IllegalAccessException e) {
|
||||||
|
throw new ConfigurationException("Failed to set value", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final class FieldPlainAccessor implements IAccessor {
|
||||||
|
@Override
|
||||||
|
public List<? extends IElement> getValues(Object theTarget) {
|
||||||
|
try {
|
||||||
|
Object values = myField.get(theTarget);
|
||||||
|
if (values == null) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
List<? extends IElement> retVal = (List<? extends IElement>) Collections.singletonList(values);
|
||||||
|
return retVal;
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
throw new ConfigurationException("Failed to get value", e);
|
||||||
|
} catch (IllegalAccessException e) {
|
||||||
|
throw new ConfigurationException("Failed to get value", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final class FieldListMutator implements IMutator {
|
||||||
|
@Override
|
||||||
|
public void addValue(Object theTarget, IElement theValue) {
|
||||||
|
try {
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
List<IElement> existingList = (List<IElement>) myField.get(theTarget);
|
||||||
|
if (existingList == null) {
|
||||||
|
existingList = new ArrayList<IElement>(2);
|
||||||
|
myField.set(theTarget, existingList);
|
||||||
|
}
|
||||||
|
existingList.add(theValue);
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
throw new ConfigurationException("Failed to set value", e);
|
||||||
|
} catch (IllegalAccessException e) {
|
||||||
|
throw new ConfigurationException("Failed to set value", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final class FieldListAccessor implements IAccessor {
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
@Override
|
||||||
|
public List<? extends IElement> getValues(Object theTarget) {
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
List<? extends IElement> retVal;
|
||||||
|
try {
|
||||||
|
retVal = (List<? extends IElement>) myField.get(theTarget);
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
throw new ConfigurationException("Failed to get value", e);
|
||||||
|
} catch (IllegalAccessException e) {
|
||||||
|
throw new ConfigurationException("Failed to get value", e);
|
||||||
|
}
|
||||||
|
if (retVal == null) {
|
||||||
|
retVal = Collections.emptyList();
|
||||||
|
}
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private final static class ListAccessor implements IAccessor {
|
private final static class ListAccessor implements IAccessor {
|
||||||
private final Method myAccessorMethod;
|
private final Method myAccessorMethod;
|
||||||
|
|
||||||
|
|
|
@ -33,6 +33,7 @@ import org.apache.commons.lang3.text.WordUtils;
|
||||||
import ca.uhn.fhir.model.api.IElement;
|
import ca.uhn.fhir.model.api.IElement;
|
||||||
import ca.uhn.fhir.model.api.IResource;
|
import ca.uhn.fhir.model.api.IResource;
|
||||||
import ca.uhn.fhir.model.dstu.resource.Patient;
|
import ca.uhn.fhir.model.dstu.resource.Patient;
|
||||||
|
import ca.uhn.fhir.model.view.ViewGenerator;
|
||||||
import ca.uhn.fhir.narrative.INarrativeGenerator;
|
import ca.uhn.fhir.narrative.INarrativeGenerator;
|
||||||
import ca.uhn.fhir.parser.IParser;
|
import ca.uhn.fhir.parser.IParser;
|
||||||
import ca.uhn.fhir.parser.JsonParser;
|
import ca.uhn.fhir.parser.JsonParser;
|
||||||
|
@ -297,4 +298,8 @@ public class FhirContext {
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ViewGenerator newViewGenerator() {
|
||||||
|
return new ViewGenerator(this);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -308,6 +308,11 @@ class ModelScanner {
|
||||||
TreeMap<Integer, BaseRuntimeDeclaredChildDefinition> orderToExtensionDef = new TreeMap<Integer, BaseRuntimeDeclaredChildDefinition>();
|
TreeMap<Integer, BaseRuntimeDeclaredChildDefinition> orderToExtensionDef = new TreeMap<Integer, BaseRuntimeDeclaredChildDefinition>();
|
||||||
|
|
||||||
LinkedList<Class<? extends ICompositeElement>> classes = new LinkedList<Class<? extends ICompositeElement>>();
|
LinkedList<Class<? extends ICompositeElement>> classes = new LinkedList<Class<? extends ICompositeElement>>();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We scan classes for annotated fields in the class but also all of its
|
||||||
|
* superclasses
|
||||||
|
*/
|
||||||
Class<? extends ICompositeElement> current = theClass;
|
Class<? extends ICompositeElement> current = theClass;
|
||||||
do {
|
do {
|
||||||
classes.push(current);
|
classes.push(current);
|
||||||
|
@ -365,8 +370,20 @@ class ModelScanner {
|
||||||
|
|
||||||
Description descriptionAnnotation = next.getAnnotation(Description.class);
|
Description descriptionAnnotation = next.getAnnotation(Description.class);
|
||||||
|
|
||||||
|
TreeMap<Integer, BaseRuntimeDeclaredChildDefinition> orderMap = theOrderToElementDef;
|
||||||
|
Extension extensionAttr = next.getAnnotation(Extension.class);
|
||||||
|
if (extensionAttr != null) {
|
||||||
|
orderMap = theOrderToExtensionDef;
|
||||||
|
}
|
||||||
|
|
||||||
String elementName = childAnnotation.name();
|
String elementName = childAnnotation.name();
|
||||||
int order = childAnnotation.order();
|
int order = childAnnotation.order();
|
||||||
|
if (order == Child.REPLACE_PARENT) {
|
||||||
|
if (true) continue; // TODO: finish implementing
|
||||||
|
for (Entry<Integer, BaseRuntimeDeclaredChildDefinition> nextEntry : orderMap.entrySet()) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
if (order < 0 && order != Child.ORDER_UNKNOWN) {
|
if (order < 0 && order != Child.ORDER_UNKNOWN) {
|
||||||
throw new ConfigurationException("Invalid order '" + order + "' on @Child for field '" + next.getName() + "' on target type: " + theClass);
|
throw new ConfigurationException("Invalid order '" + order + "' on @Child for field '" + next.getName() + "' on target type: " + theClass);
|
||||||
}
|
}
|
||||||
|
@ -375,13 +392,6 @@ class ModelScanner {
|
||||||
}
|
}
|
||||||
int min = childAnnotation.min();
|
int min = childAnnotation.min();
|
||||||
int max = childAnnotation.max();
|
int max = childAnnotation.max();
|
||||||
TreeMap<Integer, BaseRuntimeDeclaredChildDefinition> orderMap = theOrderToElementDef;
|
|
||||||
|
|
||||||
Extension extensionAttr = next.getAnnotation(Extension.class);
|
|
||||||
if (extensionAttr != null) {
|
|
||||||
orderMap = theOrderToExtensionDef;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Anything that's marked as unknown is given a new ID that is <0 so that it doesn't conflict wityh any
|
* Anything that's marked as unknown is given a new ID that is <0 so that it doesn't conflict wityh any
|
||||||
* given IDs and can be figured out later
|
* given IDs and can be figured out later
|
||||||
|
|
|
@ -48,8 +48,9 @@ public @interface Child {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constant value to supply for {@link #order()} to indicate that this child should replace the
|
* Constant value to supply for {@link #order()} to indicate that this child should replace the
|
||||||
* entry in the superclass with the same name. This may be used to indicate to parsers that
|
* entry in the superclass with the same name (and take its {@link Child#order() order} value
|
||||||
*
|
* in the process). This is useful if you wish to redefine an existing field in a resource/type
|
||||||
|
* definition in order to constrain/extend it.
|
||||||
*/
|
*/
|
||||||
int REPLACE_PARENT = -2;
|
int REPLACE_PARENT = -2;
|
||||||
|
|
||||||
|
|
|
@ -15,10 +15,16 @@ import ca.uhn.fhir.model.api.IResource;
|
||||||
|
|
||||||
public class ViewGenerator {
|
public class ViewGenerator {
|
||||||
|
|
||||||
public <T extends IResource> T newView(FhirContext theContext, IResource theResource, Class<T> theTargetType) {
|
private FhirContext myCtx;
|
||||||
|
|
||||||
|
public ViewGenerator(FhirContext theFhirContext) {
|
||||||
|
myCtx=theFhirContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T extends IResource> T newView(IResource theResource, Class<T> theTargetType) {
|
||||||
Class<? extends IResource> sourceType = theResource.getClass();
|
Class<? extends IResource> sourceType = theResource.getClass();
|
||||||
RuntimeResourceDefinition sourceDef = theContext.getResourceDefinition(theResource);
|
RuntimeResourceDefinition sourceDef = myCtx.getResourceDefinition(theResource);
|
||||||
RuntimeResourceDefinition targetDef = theContext.getResourceDefinition(theTargetType);
|
RuntimeResourceDefinition targetDef = myCtx.getResourceDefinition(theTargetType);
|
||||||
|
|
||||||
if (sourceType.equals(theTargetType)) {
|
if (sourceType.equals(theTargetType)) {
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
|
@ -45,14 +51,19 @@ public class ViewGenerator {
|
||||||
List<BaseRuntimeChildDefinition> targetChildren = theTargetDef.getChildren();
|
List<BaseRuntimeChildDefinition> targetChildren = theTargetDef.getChildren();
|
||||||
for (BaseRuntimeChildDefinition nextChild : targetChildren) {
|
for (BaseRuntimeChildDefinition nextChild : targetChildren) {
|
||||||
|
|
||||||
BaseRuntimeChildDefinition sourceChildEquivalent = theSourceDef.getChildByNameOrThrowDataFormatException(nextChild.getElementName());
|
String elementName = nextChild.getElementName();
|
||||||
|
if (nextChild.getValidChildNames().size() > 1) {
|
||||||
|
elementName = nextChild.getValidChildNames().iterator().next();
|
||||||
|
}
|
||||||
|
|
||||||
|
BaseRuntimeChildDefinition sourceChildEquivalent = theSourceDef.getChildByNameOrThrowDataFormatException(elementName);
|
||||||
if (sourceChildEquivalent == null) {
|
if (sourceChildEquivalent == null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<? extends IElement> sourceValues = sourceChildEquivalent.getAccessor().getValues(theTarget);
|
List<? extends IElement> sourceValues = sourceChildEquivalent.getAccessor().getValues(theSource);
|
||||||
for (IElement nextElement : sourceValues) {
|
for (IElement nextElement : sourceValues) {
|
||||||
nextChild.getMutator().addValue(theTargetDef, nextElement);
|
nextChild.getMutator().addValue(theTarget, nextElement);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -158,7 +158,8 @@ class ParserState<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invoked after any new XML event is individually processed, containing a copy of the XML event. This is basically intended for embedded XHTML content
|
* Invoked after any new XML event is individually processed, containing a copy of the XML event. This is basically
|
||||||
|
* intended for embedded XHTML content
|
||||||
*/
|
*/
|
||||||
public void xmlEvent(XMLEvent theNextEvent) {
|
public void xmlEvent(XMLEvent theNextEvent) {
|
||||||
myState.xmlEvent(theNextEvent);
|
myState.xmlEvent(theNextEvent);
|
||||||
|
@ -238,7 +239,8 @@ class ParserState<T> {
|
||||||
myInstance.setScheme(theValue);
|
myInstance.setScheme(theValue);
|
||||||
} else if ("value".equals(theName)) {
|
} else if ("value".equals(theName)) {
|
||||||
/*
|
/*
|
||||||
* This handles XML parsing, which is odd for this quasi-resource type, since the tag has three values instead of one like everything else.
|
* This handles XML parsing, which is odd for this quasi-resource type, since the tag has three values
|
||||||
|
* instead of one like everything else.
|
||||||
*/
|
*/
|
||||||
switch (myCatState) {
|
switch (myCatState) {
|
||||||
case STATE_LABEL:
|
case STATE_LABEL:
|
||||||
|
@ -669,11 +671,7 @@ class ParserState<T> {
|
||||||
if (myPreResourceState != null && getCurrentElement() instanceof ISupportsUndeclaredExtensions) {
|
if (myPreResourceState != null && getCurrentElement() instanceof ISupportsUndeclaredExtensions) {
|
||||||
ExtensionDt newExtension = new ExtensionDt(theIsModifier, theUrlAttr);
|
ExtensionDt newExtension = new ExtensionDt(theIsModifier, theUrlAttr);
|
||||||
ISupportsUndeclaredExtensions elem = (ISupportsUndeclaredExtensions) getCurrentElement();
|
ISupportsUndeclaredExtensions elem = (ISupportsUndeclaredExtensions) getCurrentElement();
|
||||||
if (theIsModifier) {
|
elem.addUndeclaredExtension(newExtension);
|
||||||
elem.getUndeclaredModifierExtensions().add(newExtension);
|
|
||||||
} else {
|
|
||||||
elem.getUndeclaredExtensions().add(newExtension);
|
|
||||||
}
|
|
||||||
ExtensionState newState = new ExtensionState(myPreResourceState, newExtension);
|
ExtensionState newState = new ExtensionState(myPreResourceState, newExtension);
|
||||||
push(newState);
|
push(newState);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
package ca.uhn.fhir.model.view;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.model.api.annotation.Child;
|
||||||
|
import ca.uhn.fhir.model.api.annotation.Extension;
|
||||||
|
import ca.uhn.fhir.model.api.annotation.ResourceDef;
|
||||||
|
import ca.uhn.fhir.model.dstu.resource.Patient;
|
||||||
|
import ca.uhn.fhir.model.primitive.IntegerDt;
|
||||||
|
|
||||||
|
@ResourceDef(name = "Patient")
|
||||||
|
public class ExtPatient extends Patient {
|
||||||
|
|
||||||
|
@Extension(url = "urn:ext", isModifier = false, definedLocally = false)
|
||||||
|
@Child(name = "ext")
|
||||||
|
private IntegerDt myExt;
|
||||||
|
|
||||||
|
@Extension(url = "urn:modExt", isModifier = false, definedLocally = false)
|
||||||
|
@Child(name = "modExt")
|
||||||
|
private IntegerDt myModExt;
|
||||||
|
|
||||||
|
public IntegerDt getExt() {
|
||||||
|
if (myExt == null) {
|
||||||
|
myExt = new IntegerDt();
|
||||||
|
}
|
||||||
|
return myExt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setExt(IntegerDt theExt) {
|
||||||
|
myExt = theExt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IntegerDt getModExt() {
|
||||||
|
if (myModExt == null) {
|
||||||
|
myModExt = new IntegerDt();
|
||||||
|
}
|
||||||
|
return myModExt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setModExt(IntegerDt theModExt) {
|
||||||
|
myModExt = theModExt;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,61 @@
|
||||||
|
package ca.uhn.fhir.model.view;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
|
import ca.uhn.fhir.model.api.ExtensionDt;
|
||||||
|
import ca.uhn.fhir.model.dstu.resource.Patient;
|
||||||
|
import ca.uhn.fhir.model.primitive.IntegerDt;
|
||||||
|
import ca.uhn.fhir.parser.IParser;
|
||||||
|
|
||||||
|
public class ViewGeneratorTest {
|
||||||
|
|
||||||
|
private static FhirContext ourCtx = new FhirContext();
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testView() {
|
||||||
|
|
||||||
|
ExtPatient src = new ExtPatient();
|
||||||
|
src.addIdentifier("urn:sys", "id1");
|
||||||
|
src.addIdentifier("urn:sys", "id2");
|
||||||
|
src.getExt().setValue(100);
|
||||||
|
src.getModExt().setValue(200);
|
||||||
|
|
||||||
|
String enc = ourCtx.newXmlParser().encodeResourceToString(src);
|
||||||
|
IParser parser = ourCtx.newXmlParser();
|
||||||
|
Patient nonExt = parser.parseResource(Patient.class, enc);
|
||||||
|
|
||||||
|
assertEquals(Patient.class, nonExt.getClass());
|
||||||
|
assertEquals("urn:sys", nonExt.getIdentifier().get(0).getSystem().getValueAsString());
|
||||||
|
assertEquals("id1", nonExt.getIdentifier().get(0).getValue().getValue());
|
||||||
|
assertEquals("urn:sys", nonExt.getIdentifier().get(1).getSystem().getValueAsString());
|
||||||
|
assertEquals("id2", nonExt.getIdentifier().get(1).getValue().getValueAsString());
|
||||||
|
|
||||||
|
List<ExtensionDt> ext = nonExt.getUndeclaredExtensionsByUrl("urn:ext");
|
||||||
|
assertEquals(1,ext.size());
|
||||||
|
assertEquals("urn:ext", ext.get(0).getUrlAsString());
|
||||||
|
assertEquals(IntegerDt.class, ext.get(0).getValueAsPrimitive().getClass());
|
||||||
|
assertEquals("100", ext.get(0).getValueAsPrimitive().getValueAsString());
|
||||||
|
|
||||||
|
List<ExtensionDt> modExt = nonExt.getUndeclaredExtensionsByUrl("urn:modExt");
|
||||||
|
assertEquals(1,modExt.size());
|
||||||
|
assertEquals("urn:modExt", modExt.get(0).getUrlAsString());
|
||||||
|
assertEquals(IntegerDt.class, modExt.get(0).getValueAsPrimitive().getClass());
|
||||||
|
assertEquals("200", modExt.get(0).getValueAsPrimitive().getValueAsString());
|
||||||
|
|
||||||
|
ExtPatient va = ourCtx.newViewGenerator().newView(nonExt, ExtPatient.class);
|
||||||
|
assertEquals("urn:sys", va.getIdentifier().get(0).getSystem().getValueAsString());
|
||||||
|
assertEquals("id1", va.getIdentifier().get(0).getValue().getValue());
|
||||||
|
assertEquals("urn:sys", va.getIdentifier().get(1).getSystem().getValueAsString());
|
||||||
|
assertEquals("id2", va.getIdentifier().get(1).getValue().getValueAsString());
|
||||||
|
assertEquals(100, va.getExt().getValue().intValue());
|
||||||
|
assertEquals(200, va.getModExt().getValue().intValue());
|
||||||
|
assertEquals(0, va.getAllUndeclaredExtensions().size());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -51,6 +51,8 @@ import ca.uhn.fhir.model.dstu.resource.Conformance;
|
||||||
import ca.uhn.fhir.model.dstu.resource.Conformance.Rest;
|
import ca.uhn.fhir.model.dstu.resource.Conformance.Rest;
|
||||||
import ca.uhn.fhir.model.dstu.resource.Conformance.RestQuery;
|
import ca.uhn.fhir.model.dstu.resource.Conformance.RestQuery;
|
||||||
import ca.uhn.fhir.model.dstu.resource.Conformance.RestResource;
|
import ca.uhn.fhir.model.dstu.resource.Conformance.RestResource;
|
||||||
|
import ca.uhn.fhir.model.dstu.resource.Conformance.RestResourceSearchParam;
|
||||||
|
import ca.uhn.fhir.model.dstu.valueset.SearchParamTypeEnum;
|
||||||
import ca.uhn.fhir.model.primitive.DateTimeDt;
|
import ca.uhn.fhir.model.primitive.DateTimeDt;
|
||||||
import ca.uhn.fhir.model.primitive.DecimalDt;
|
import ca.uhn.fhir.model.primitive.DecimalDt;
|
||||||
import ca.uhn.fhir.model.primitive.IdDt;
|
import ca.uhn.fhir.model.primitive.IdDt;
|
||||||
|
@ -325,6 +327,7 @@ public class Controller {
|
||||||
RuntimeResourceDefinition def = myCtx.getResourceDefinition(theRequest.getResource());
|
RuntimeResourceDefinition def = myCtx.getResourceDefinition(theRequest.getResource());
|
||||||
|
|
||||||
TreeSet<String> includes = new TreeSet<String>();
|
TreeSet<String> includes = new TreeSet<String>();
|
||||||
|
TreeSet<String> sortParams = new TreeSet<String>();
|
||||||
List<RestQuery> queries = new ArrayList<Conformance.RestQuery>();
|
List<RestQuery> queries = new ArrayList<Conformance.RestQuery>();
|
||||||
boolean haveSearchParams = false;
|
boolean haveSearchParams = false;
|
||||||
List<List<String>> queryIncludes = new ArrayList<List<String>>();
|
List<List<String>> queryIncludes = new ArrayList<List<String>>();
|
||||||
|
@ -336,6 +339,11 @@ public class Controller {
|
||||||
includes.add(next.getValue());
|
includes.add(next.getValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for (RestResourceSearchParam next : nextRes.getSearchParam()) {
|
||||||
|
if (next.getType().getValueAsEnum() != SearchParamTypeEnum.COMPOSITE) {
|
||||||
|
sortParams.add(next.getName().getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
if (nextRes.getSearchParam().size() > 0) {
|
if (nextRes.getSearchParam().size() > 0) {
|
||||||
haveSearchParams = true;
|
haveSearchParams = true;
|
||||||
}
|
}
|
||||||
|
@ -370,6 +378,7 @@ public class Controller {
|
||||||
theModel.put("queries", queries);
|
theModel.put("queries", queries);
|
||||||
theModel.put("haveSearchParams", haveSearchParams);
|
theModel.put("haveSearchParams", haveSearchParams);
|
||||||
theModel.put("queryIncludes", queryIncludes);
|
theModel.put("queryIncludes", queryIncludes);
|
||||||
|
theModel.put("sortParams", sortParams);
|
||||||
|
|
||||||
if (isNotBlank(theRequest.getUpdateId())) {
|
if (isNotBlank(theRequest.getUpdateId())) {
|
||||||
String updateId = theRequest.getUpdateId();
|
String updateId = theRequest.getUpdateId();
|
||||||
|
|
|
@ -145,20 +145,18 @@
|
||||||
<div class='col-sm-3'>
|
<div class='col-sm-3'>
|
||||||
|
|
||||||
<div class="btn-group">
|
<div class="btn-group">
|
||||||
<button type="button" class="btn btn-info">Action</button>
|
<input type="hidden" id="search_sort" />
|
||||||
|
<button type="button" class="btn btn-info" id="search_sort_button">Default Sort</button>
|
||||||
<button type="button" class="btn btn-info dropdown-toggle" data-toggle="dropdown">
|
<button type="button" class="btn btn-info dropdown-toggle" data-toggle="dropdown">
|
||||||
<span class="caret"></span>
|
<span class="caret"></span>
|
||||||
<span class="sr-only">Default Sort</span>
|
<span class="sr-only">Default Sort</span>
|
||||||
</button>
|
</button>
|
||||||
<ul class="dropdown-menu" role="menu">
|
<ul class="dropdown-menu" role="menu">
|
||||||
<li><a href="#">Default Sort</a></li>
|
<li><a href="javascript:updateSort('');">Default Sort</a></li>
|
||||||
<li class="divider"></li>
|
<li class="divider"></li>
|
||||||
<li><a href="#">Another action</a></li>
|
<li th:each="param : ${sortParams}"><a th:href="'javascript:updateSort(\'' + ${param} + '\');'" th:text="${param}"></a></li>
|
||||||
<li><a href="#">Something else here</a></li>
|
|
||||||
<li><a href="#">Separated link</a></li>
|
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<br clear="all"/>
|
<br clear="all"/>
|
||||||
|
|
|
@ -393,6 +393,15 @@ function setResource(target, resourceName) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function updateSort(value) {
|
||||||
|
$('#search_sort').val(value);
|
||||||
|
if (value == '') {
|
||||||
|
$('#search_sort_button').text('Default Sort');
|
||||||
|
} else {
|
||||||
|
$('#search_sort_button').text(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$( document ).ready(function() {
|
$( document ).ready(function() {
|
||||||
addSearchParamRow();
|
addSearchParamRow();
|
||||||
});
|
});
|
Loading…
Reference in New Issue