Doc updates and allow DSTU3 resources in some annotations that

previously didn't allow it
This commit is contained in:
James Agnew 2017-05-14 22:03:38 -04:00
parent da2d7c3bc3
commit 48520832ef
9 changed files with 107 additions and 116 deletions

View File

@ -10,30 +10,20 @@ import java.util.Set;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import org.hl7.fhir.dstu3.model.IdType; import org.hl7.fhir.dstu3.model.*;
import org.hl7.fhir.dstu3.model.Bundle.BundleEntryComponent;
import org.hl7.fhir.dstu3.model.Identifier.IdentifierUse;
import org.hl7.fhir.dstu3.model.OperationOutcome.IssueSeverity;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType;
import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.Bundle;
import ca.uhn.fhir.model.api.BundleEntry;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.api.Include; import ca.uhn.fhir.model.api.Include;
import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum; import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
import ca.uhn.fhir.model.api.Tag; import ca.uhn.fhir.model.api.Tag;
import ca.uhn.fhir.model.api.TagList; import ca.uhn.fhir.model.api.TagList;
import ca.uhn.fhir.model.api.TemporalPrecisionEnum; import ca.uhn.fhir.model.api.TemporalPrecisionEnum;
import ca.uhn.fhir.model.api.annotation.Description; import ca.uhn.fhir.model.api.annotation.Description;
import ca.uhn.fhir.model.base.composite.BaseCodingDt;
import ca.uhn.fhir.model.dstu2.resource.Conformance;
import ca.uhn.fhir.model.dstu2.resource.DiagnosticReport;
import ca.uhn.fhir.model.dstu2.resource.Observation;
import ca.uhn.fhir.model.dstu2.resource.OperationOutcome;
import ca.uhn.fhir.model.dstu2.resource.Organization;
import ca.uhn.fhir.model.dstu2.resource.Patient;
import ca.uhn.fhir.model.dstu2.valueset.IdentifierUseEnum;
import ca.uhn.fhir.model.dstu2.valueset.IssueSeverityEnum;
import ca.uhn.fhir.model.primitive.DateTimeDt;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.model.primitive.InstantDt;
import ca.uhn.fhir.parser.DataFormatException; import ca.uhn.fhir.parser.DataFormatException;
import ca.uhn.fhir.rest.annotation.AddTags; import ca.uhn.fhir.rest.annotation.AddTags;
import ca.uhn.fhir.rest.annotation.At; import ca.uhn.fhir.rest.annotation.At;
@ -142,13 +132,13 @@ public List<Patient> search(
public class PatientRp implements IResourceProvider { public class PatientRp implements IResourceProvider {
@Override @Override
public Class<? extends IResource> getResourceType() { public Class<? extends IBaseResource> getResourceType() {
return Patient.class; return Patient.class;
} }
@Search(compartmentName="Condition") @Search(compartmentName="Condition")
public List<IResource> searchCompartment(@IdParam IdDt thePatientId) { public List<IBaseResource> searchCompartment(@IdParam IdType thePatientId) {
List<IResource> retVal=new ArrayList<IResource>(); List<IBaseResource> retVal=new ArrayList<IBaseResource>();
// populate this with resources of any type that are a part of the // populate this with resources of any type that are a part of the
// "Condition" compartment for the Patient with ID "thePatientId" // "Condition" compartment for the Patient with ID "thePatientId"
@ -200,26 +190,27 @@ public List<Patient> findPatients(
//START SNIPPET: referenceSimple //START SNIPPET: referenceSimple
@Search @Search
public List<Patient> findPatientsWithSimpleReference( public List<DiagnosticReport> findDiagnosticReportsWithSubjet(
@OptionalParam(name=Patient.SP_CAREPROVIDER) ReferenceParam theProvider @OptionalParam(name=DiagnosticReport.SP_SUBJECT) ReferenceParam theSubject
) { ) {
List<Patient> retVal=new ArrayList<Patient>(); List<DiagnosticReport> retVal=new ArrayList<DiagnosticReport>();
// If the parameter passed in includes a resource type (e.g. ?provider:Patient=123) // If the parameter passed in includes a resource type (e.g. ?subject:Patient=123)
// that resoruce type is available. Here we just check that it is either not provided // that resource type is available. Here we just check that it is either not provided
// or set to "Patient" // or set to "Patient"
if (theProvider.hasResourceType()) { if (theSubject.hasResourceType()) {
String resourceType = theProvider.getResourceType(); String resourceType = theSubject.getResourceType();
if ("Patient".equals(resourceType) == false) { if ("Patient".equals(resourceType) == false) {
throw new InvalidRequestException("Invalid resource type for parameter 'provider': " + resourceType); throw new InvalidRequestException("Invalid resource type for parameter 'subject': " + resourceType);
} }
} }
if (theProvider != null) { if (theSubject != null) {
// ReferenceParam extends IdDt so all of the resource ID methods are available // ReferenceParam extends IdType so all of the resource ID methods are available
String providerId = theProvider.getIdPart(); String subjectId = theSubject.getIdPart();
// .. populate retVal will Patient resources having provider with id "providerId" .. // .. populate retVal with DiagnosticReport resources having
// subject with id "subjectId" ..
} }
@ -314,7 +305,7 @@ public List<Observation> findBySubject(
// Because the chained parameter "subject.birthdate" is actually of type // Because the chained parameter "subject.birthdate" is actually of type
// "date", we convert the value to a date before processing it. // "date", we convert the value to a date before processing it.
DateParam dateSubject = subject.toDateParam(myContext); DateParam dateSubject = subject.toDateParam(myContext);
DateTimeDt birthDate = dateSubject.getValueAsDateTimeDt(); DateTimeType birthDate = new DateTimeType(dateSubject.getValueAsString());
// TODO: populate all the observations for the birthdate // TODO: populate all the observations for the birthdate
@ -332,17 +323,17 @@ public List<Observation> findBySubject(
//START SNIPPET: read //START SNIPPET: read
@Read() @Read()
public Patient getResourceById(@IdParam IdDt theId) { public Patient getResourceById(@IdParam IdType theId) {
Patient retVal = new Patient(); Patient retVal = new Patient();
// ...populate... // ...populate...
retVal.addIdentifier().setSystem("urn:mrns").setValue("12345"); retVal.addIdentifier().setSystem("urn:mrns").setValue("12345");
retVal.addName().addFamily("Smith").addGiven("Tester").addGiven("Q"); retVal.addName().setFamily("Smith").addGiven("Tester").addGiven("Q");
// ...etc... // ...etc...
// if you know the version ID of the resource, you should set it and HAPI will // if you know the version ID of the resource, you should set it and HAPI will
// include it in a Content-Location header // include it in a Content-Location header
retVal.setId(new IdDt("Patient", "123", "2")); retVal.setId(new IdType("Patient", "123", "2"));
return retVal; return retVal;
} }
@ -350,7 +341,7 @@ public Patient getResourceById(@IdParam IdDt theId) {
//START SNIPPET: delete //START SNIPPET: delete
@Delete() @Delete()
public void deletePatient(@IdParam IdDt theId) { public void deletePatient(@IdParam IdType theId) {
// .. Delete the patient .. // .. Delete the patient ..
if (couldntFindThisId) { if (couldntFindThisId) {
throw new ResourceNotFoundException("Unknown version"); throw new ResourceNotFoundException("Unknown version");
@ -366,7 +357,7 @@ public void deletePatient(@IdParam IdDt theId) {
//START SNIPPET: deleteConditional //START SNIPPET: deleteConditional
@Delete() @Delete()
public void deletePatientConditional(@IdParam IdDt theId, @ConditionalUrlParam String theConditionalUrl) { public void deletePatientConditional(@IdParam IdType theId, @ConditionalUrlParam String theConditionalUrl) {
// Only one of theId or theConditionalUrl will have a value depending // Only one of theId or theConditionalUrl will have a value depending
// on whether the URL receieved was a logical ID, or a conditional // on whether the URL receieved was a logical ID, or a conditional
// search string // search string
@ -384,14 +375,14 @@ public void deletePatientConditional(@IdParam IdDt theId, @ConditionalUrlParam S
//START SNIPPET: history //START SNIPPET: history
@History() @History()
public List<Patient> getPatientHistory( public List<Patient> getPatientHistory(
@IdParam IdDt theId, @IdParam IdType theId,
@Since InstantDt theSince, @Since InstantType theSince,
@At DateRangeParam theAt @At DateRangeParam theAt
) { ) {
List<Patient> retVal = new ArrayList<Patient>(); List<Patient> retVal = new ArrayList<Patient>();
Patient patient = new Patient(); Patient patient = new Patient();
patient.addName().addFamily("Smith"); patient.addName().setFamily("Smith");
// Set the ID and version // Set the ID and version
patient.setId(theId.withVersion("1")); patient.setId(theId.withVersion("1"));
@ -404,7 +395,7 @@ public List<Patient> getPatientHistory(
//START SNIPPET: vread //START SNIPPET: vread
@Read(version=true) @Read(version=true)
public Patient readOrVread(@IdParam IdDt theId) { public Patient readOrVread(@IdParam IdType theId) {
Patient retVal = new Patient(); Patient retVal = new Patient();
if (theId.hasVersionIdPart()) { if (theId.hasVersionIdPart()) {
@ -433,14 +424,14 @@ public List<Patient> searchByLastName(@RequiredParam(name=Patient.SP_FAMILY) Str
// ...populate... // ...populate...
Patient patient = new Patient(); Patient patient = new Patient();
patient.addIdentifier().setSystem("urn:mrns").setValue("12345"); patient.addIdentifier().setSystem("urn:mrns").setValue("12345");
patient.addName().addFamily("Smith").addGiven("Tester").addGiven("Q"); patient.addName().setFamily("Smith").addGiven("Tester").addGiven("Q");
// ...etc... // ...etc...
// Every returned resource must have its logical ID set. If the server // Every returned resource must have its logical ID set. If the server
// supports versioning, that should be set too // supports versioning, that should be set too
String logicalId = "4325"; String logicalId = "4325";
String versionId = "2"; // optional String versionId = "2"; // optional
patient.setId(new IdDt("Patient", logicalId, versionId)); patient.setId(new IdType("Patient", logicalId, versionId));
/* /*
* This is obviously a fairly contrived example since we are always * This is obviously a fairly contrived example since we are always
@ -531,7 +522,7 @@ public List<Observation> searchByObservationNames(
// The list here will contain 0..* codings, and any observations which match any of the // The list here will contain 0..* codings, and any observations which match any of the
// given codings should be returned // given codings should be returned
List<BaseCodingDt> wantedCodings = theCodings.getListAsCodings(); List<TokenParam> wantedCodings = theCodings.getValuesAsQueryTokens();
List<Observation> retVal = new ArrayList<Observation>(); List<Observation> retVal = new ArrayList<Observation>();
// ...populate... // ...populate...
@ -605,7 +596,7 @@ private ITestClient provideTc() {
return null; return null;
} }
@Override @Override
public Class<? extends IResource> getResourceType() { public Class<? extends IBaseResource> getResourceType() {
return null; return null;
} }
@ -629,7 +620,7 @@ public List<DiagnosticReport> getDiagnosticReport(
if (theIncludes.contains(new Include("DiagnosticReport:subject"))) { if (theIncludes.contains(new Include("DiagnosticReport:subject"))) {
// The resource reference should contain the ID of the patient // The resource reference should contain the ID of the patient
IdDt subjectId = report.getSubject().getReference(); IIdType subjectId = report.getSubject().getReferenceElement();
// So load the patient ID and return it // So load the patient ID and return it
Patient subject = loadSomePatientFromDatabase(subjectId); Patient subject = loadSomePatientFromDatabase(subjectId);
@ -677,7 +668,7 @@ public List<DiagnosticReport> getDiagnosticReport(
if ("DiagnosticReport:subject".equals(theInclude)) { if ("DiagnosticReport:subject".equals(theInclude)) {
// The resource reference should contain the ID of the patient // The resource reference should contain the ID of the patient
IdDt subjectId = report.getSubject().getReference(); IIdType subjectId = report.getSubject().getReferenceElement();
// So load the patient ID and return it // So load the patient ID and return it
Patient subject = loadSomePatientFromDatabase(subjectId); Patient subject = loadSomePatientFromDatabase(subjectId);
@ -711,7 +702,7 @@ private DiagnosticReport loadSomeDiagnosticReportFromDatabase(TokenParam theIden
return null; return null;
} }
private Patient loadSomePatientFromDatabase(IdDt theId) { private Patient loadSomePatientFromDatabase(IIdType theId) {
return null; return null;
} }
@ -740,7 +731,7 @@ public MethodOutcome createPatient(@ResourceParam Patient thePatient) {
// the ID (composed of the type Patient, the logical ID 3746, and the // the ID (composed of the type Patient, the logical ID 3746, and the
// version ID 1) // version ID 1)
MethodOutcome retVal = new MethodOutcome(); MethodOutcome retVal = new MethodOutcome();
retVal.setId(new IdDt("Patient", "3746", "1")); retVal.setId(new IdType("Patient", "3746", "1"));
// You can also add an OperationOutcome resource to return // You can also add an OperationOutcome resource to return
// This part is optional though: // This part is optional though:
@ -785,7 +776,7 @@ public abstract MethodOutcome createNewPatient(@ResourceParam Patient thePatient
@Update @Update
public MethodOutcome updatePatientConditional( public MethodOutcome updatePatientConditional(
@ResourceParam Patient thePatient, @ResourceParam Patient thePatient,
@IdParam IdDt theId, @IdParam IdType theId,
@ConditionalUrlParam String theConditional) { @ConditionalUrlParam String theConditional) {
// Only one of theId or theConditional will have a value and the other will be null, // Only one of theId or theConditional will have a value and the other will be null,
@ -804,15 +795,15 @@ public MethodOutcome updatePatientConditional(
@Update @Update
public MethodOutcome updatePatientPrefer( public MethodOutcome updatePatientPrefer(
@ResourceParam Patient thePatient, @ResourceParam Patient thePatient,
@IdParam IdDt theId) { @IdParam IdType theId) {
// Save the patient to the database // Save the patient to the database
// Update the version and last updated time on the resource // Update the version and last updated time on the resource
IdDt updatedId = theId.withVersion("123"); IdType updatedId = theId.withVersion("123");
thePatient.setId(updatedId); thePatient.setId(updatedId);
InstantDt lastUpdated = InstantDt.withCurrentTime(); InstantType lastUpdated = InstantType.withCurrentTime();
ResourceMetadataKeyEnum.UPDATED.put(thePatient, lastUpdated); thePatient.getMeta().setLastUpdatedElement(lastUpdated);
// Add the resource to the outcome, so that it can be returned by the server // Add the resource to the outcome, so that it can be returned by the server
// if the client requests it // if the client requests it
@ -827,7 +818,7 @@ public MethodOutcome updatePatientPrefer(
@Update @Update
public MethodOutcome updatePatientWithRawValue ( public MethodOutcome updatePatientWithRawValue (
@ResourceParam Patient thePatient, @ResourceParam Patient thePatient,
@IdParam IdDt theId, @IdParam IdType theId,
@ResourceParam String theRawBody, @ResourceParam String theRawBody,
@ResourceParam EncodingEnum theEncodingEnum) { @ResourceParam EncodingEnum theEncodingEnum) {
@ -842,7 +833,7 @@ public MethodOutcome updatePatientWithRawValue (
//START SNIPPET: update //START SNIPPET: update
@Update @Update
public MethodOutcome updatePatient(@IdParam IdDt theId, @ResourceParam Patient thePatient) { public MethodOutcome updatePatient(@IdParam IdType theId, @ResourceParam Patient thePatient) {
/* /*
* First we might want to do business validation. The UnprocessableEntityException * First we might want to do business validation. The UnprocessableEntityException
@ -895,7 +886,7 @@ public MethodOutcome updatePatient(@IdParam IdDt theId, @ResourceParam Patient t
//START SNIPPET: updateClient //START SNIPPET: updateClient
@Update @Update
public abstract MethodOutcome updateSomePatient(@IdParam IdDt theId, @ResourceParam Patient thePatient); public abstract MethodOutcome updateSomePatient(@IdParam IdType theId, @ResourceParam Patient thePatient);
//END SNIPPET: updateClient //END SNIPPET: updateClient
//START SNIPPET: validate //START SNIPPET: validate
@ -921,7 +912,7 @@ public MethodOutcome validatePatient(@ResourceParam Patient thePatient,
// You may also add an OperationOutcome resource to return // You may also add an OperationOutcome resource to return
// This part is optional though: // This part is optional though:
OperationOutcome outcome = new OperationOutcome(); OperationOutcome outcome = new OperationOutcome();
outcome.addIssue().setSeverity(IssueSeverityEnum.WARNING).setDiagnostics("One minor issue detected"); outcome.addIssue().setSeverity(IssueSeverity.WARNING).setDiagnostics("One minor issue detected");
retVal.setOperationOutcome(outcome); retVal.setOperationOutcome(outcome);
return retVal; return retVal;
@ -939,16 +930,16 @@ public static void main(String[] args) throws DataFormatException, IOException {
private void savePatientToDatabase(Patient thePatient) { private void savePatientToDatabase(Patient thePatient) {
// nothing // nothing
} }
private void savePatientToDatabase(IdDt theId, Patient thePatient) { private void savePatientToDatabase(IdType theId, Patient thePatient) {
// nothing // nothing
} }
//START SNIPPET: metadataProvider //START SNIPPET: metadataProvider
public class ConformanceProvider { public class CapabilityStatementProvider {
@Metadata @Metadata
public Conformance getServerMetadata() { public CapabilityStatement getServerMetadata() {
Conformance retVal = new Conformance(); CapabilityStatement retVal = new CapabilityStatement();
// ..populate.. // ..populate..
return retVal; return retVal;
} }
@ -962,7 +953,7 @@ public class ConformanceProvider {
public interface MetadataClient extends IRestfulClient { public interface MetadataClient extends IRestfulClient {
@Metadata @Metadata
Conformance getServerMetadata(); CapabilityStatement getServerMetadata();
// ....Other methods can also be added as usual.... // ....Other methods can also be added as usual....
@ -981,7 +972,7 @@ public interface HistoryClient extends IBasicClient {
/** Instance level (history of a specific resource instance by type and ID) */ /** Instance level (history of a specific resource instance by type and ID) */
@History(type=Patient.class) @History(type=Patient.class)
Bundle getHistoryPatientInstance(@IdParam IdDt theId); Bundle getHistoryPatientInstance(@IdParam IdType theId);
/** /**
* Either (or both) of the "since" and "count" paramaters can * Either (or both) of the "since" and "count" paramaters can
@ -998,26 +989,22 @@ public void bbbbb() throws DataFormatException, IOException {
//START SNIPPET: metadataClientUsage //START SNIPPET: metadataClientUsage
FhirContext ctx = FhirContext.forDstu2(); FhirContext ctx = FhirContext.forDstu2();
MetadataClient client = ctx.newRestfulClient(MetadataClient.class, "http://spark.furore.com/fhir"); MetadataClient client = ctx.newRestfulClient(MetadataClient.class, "http://spark.furore.com/fhir");
Conformance metadata = client.getServerMetadata(); CapabilityStatement metadata = client.getServerMetadata();
System.out.println(ctx.newXmlParser().encodeResourceToString(metadata)); System.out.println(ctx.newXmlParser().encodeResourceToString(metadata));
//END SNIPPET: metadataClientUsage //END SNIPPET: metadataClientUsage
} }
//START SNIPPET: readTags //START SNIPPET: readTags
@Read() @Read()
public Patient readPatient(@IdParam IdDt theId) { public Patient readPatient(@IdParam IdType theId) {
Patient retVal = new Patient(); Patient retVal = new Patient();
// ..populate demographics, contact, or anything else you usually would.. // ..populate demographics, contact, or anything else you usually would..
// Create a TagList and place a complete list of the patient's tags inside // Populate some tags
TagList tags = new TagList(); retVal.getMeta().addTag("http://animals", "Dog", "Canine Patient"); // TODO: more realistic example
tags.addTag("http://animals", "Dog", "Canine Patient"); // TODO: more realistic example retVal.getMeta().addTag("http://personality", "Friendly", "Friendly"); // TODO: more realistic example
tags.addTag("http://personality", "Friendly", "Friendly"); // TODO: more realistic example
// The tags are then stored in the Patient resource instance
retVal.getResourceMetadata().put(ResourceMetadataKeyEnum.TAG_LIST, tags);
return retVal; return retVal;
} }
//END SNIPPET: readTags //END SNIPPET: readTags
@ -1027,7 +1014,7 @@ private interface IPatientClient extends IBasicClient
{ {
/** Read a patient from a server by ID */ /** Read a patient from a server by ID */
@Read @Read
Patient readPatient(@IdParam IdDt theId); Patient readPatient(@IdParam IdType theId);
// Only one method is shown here, but many methods may be // Only one method is shown here, but many methods may be
// added to the same client interface! // added to the same client interface!
@ -1037,11 +1024,11 @@ private interface IPatientClient extends IBasicClient
public void clientRead() { public void clientRead() {
//START SNIPPET: clientReadTags //START SNIPPET: clientReadTags
IPatientClient client = FhirContext.forDstu2().newRestfulClient(IPatientClient.class, "http://foo/fhir"); IPatientClient client = FhirContext.forDstu2().newRestfulClient(IPatientClient.class, "http://foo/fhir");
Patient patient = client.readPatient(new IdDt("1234")); Patient patient = client.readPatient(new IdType("1234"));
// Access the tag list // Access the tag list
TagList tagList = (TagList) patient.getResourceMetadata().get(ResourceMetadataKeyEnum.TAG_LIST); List<Coding> tagList = patient.getMeta().getTag();
for (Tag next : tagList) { for (Coding next : tagList) {
// ..process the tags somehow.. // ..process the tags somehow..
} }
//END SNIPPET: clientReadTags //END SNIPPET: clientReadTags
@ -1050,14 +1037,12 @@ for (Tag next : tagList) {
Patient newPatient = new Patient(); Patient newPatient = new Patient();
// Populate the resource object // Populate the resource object
newPatient.addIdentifier().setUse(IdentifierUseEnum.OFFICIAL).setValue("123"); newPatient.addIdentifier().setUse(IdentifierUse.OFFICIAL).setValue("123");
newPatient.addName().addFamily("Jones").addGiven("Frank"); newPatient.addName().setFamily("Jones").addGiven("Frank");
// Populate tags // Populate some tags
TagList tags = new TagList(); newPatient.getMeta().addTag("http://animals", "Dog", "Canine Patient"); // TODO: more realistic example
tags.addTag("http://animals", "Dog", "Canine Patient"); // TODO: more realistic example newPatient.getMeta().addTag("http://personality", "Friendly", "Friendly"); // TODO: more realistic example
tags.addTag("http://personality", "Friendly", "Friendly"); // TODO: more realistic example
newPatient.getResourceMetadata().put(ResourceMetadataKeyEnum.TAG_LIST, tags);
// ...invoke the create method on the client... // ...invoke the create method on the client...
//END SNIPPET: clientCreateTags //END SNIPPET: clientCreateTags
@ -1068,11 +1053,11 @@ newPatient.getResourceMetadata().put(ResourceMetadataKeyEnum.TAG_LIST, tags);
public MethodOutcome createPatientResource(@ResourceParam Patient thePatient) { public MethodOutcome createPatientResource(@ResourceParam Patient thePatient) {
// ..save the resouce.. // ..save the resouce..
IdDt id = new IdDt("123"); // the new databse primary key for this resource IdType id = new IdType("123"); // the new databse primary key for this resource
// Get the tag list // Get the tag list
TagList tags = (TagList) thePatient.getResourceMetadata().get(ResourceMetadataKeyEnum.TAG_LIST); List<Coding> tags = thePatient.getMeta().getTag();
for (Tag tag : tags) { for (Coding tag : tags) {
// process/save each tag somehow // process/save each tag somehow
} }
@ -1099,34 +1084,34 @@ public class TagMethodProvider
/** Return a list of all tags that exist on a specific instance /** Return a list of all tags that exist on a specific instance
* of the given resource type */ * of the given resource type */
@GetTags(type=Patient.class) @GetTags(type=Patient.class)
public TagList getTagsForResources(@IdParam IdDt theId) { public TagList getTagsForResources(@IdParam IdType theId) {
return new TagList(); // populate this return new TagList(); // populate this
} }
/** Return a list of all tags that exist on a specific version /** Return a list of all tags that exist on a specific version
* of the given resource type */ * of the given resource type */
@GetTags(type=Patient.class) @GetTags(type=Patient.class)
public TagList getTagsForResourceVersion(@IdParam IdDt theId) { public TagList getTagsForResourceVersion(@IdParam IdType theId) {
return new TagList(); // populate this return new TagList(); // populate this
} }
/** Add tags to a resource */ /** Add tags to a resource */
@AddTags(type=Patient.class) @AddTags(type=Patient.class)
public void getTagsForResourceVersion(@IdParam IdDt theId, public void getTagsForResourceVersion(@IdParam IdType theId,
@TagListParam TagList theTagList) { @TagListParam TagList theTagList) {
// add tags // add tags
} }
/** Add tags to a resource version */ /** Add tags to a resource version */
@AddTags(type=Patient.class) @AddTags(type=Patient.class)
public void addTagsToResourceVersion(@IdParam IdDt theId, public void addTagsToResourceVersion(@IdParam IdType theId,
@TagListParam TagList theTagList) { @TagListParam TagList theTagList) {
// add tags // add tags
} }
/** Remove tags from a resource */ /** Remove tags from a resource */
@DeleteTags(type=Patient.class) @DeleteTags(type=Patient.class)
public void deleteTagsFromResourceVersion(@IdParam IdDt theId, public void deleteTagsFromResourceVersion(@IdParam IdType theId,
@TagListParam TagList theTagList) { @TagListParam TagList theTagList) {
// add tags // add tags
} }
@ -1137,7 +1122,7 @@ public class TagMethodProvider
//START SNIPPET: transaction //START SNIPPET: transaction
@Transaction @Transaction
public Bundle transaction(@TransactionParam Bundle theInput) { public Bundle transaction(@TransactionParam Bundle theInput) {
for (BundleEntry nextEntry : theInput.getEntries()) { for (BundleEntryComponent nextEntry : theInput.getEntry()) {
// Process entry // Process entry
} }

View File

@ -25,6 +25,8 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; import java.lang.annotation.Target;
import org.hl7.fhir.instance.model.api.IBaseResource;
import ca.uhn.fhir.model.api.IResource; import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.api.TagList; import ca.uhn.fhir.model.api.TagList;
import ca.uhn.fhir.model.primitive.IdDt; import ca.uhn.fhir.model.primitive.IdDt;
@ -74,6 +76,6 @@ public @interface AddTags {
* , this method is expected to return a TagList containing only tags which * , this method is expected to return a TagList containing only tags which
* are specific to the given resource type. * are specific to the given resource type.
*/ */
Class<? extends IResource> type() default IResource.class; Class<? extends IBaseResource> type() default IBaseResource.class;
} }

View File

@ -25,6 +25,8 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; import java.lang.annotation.Target;
import org.hl7.fhir.instance.model.api.IBaseResource;
import ca.uhn.fhir.model.api.IResource; import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.api.TagList; import ca.uhn.fhir.model.api.TagList;
import ca.uhn.fhir.model.primitive.IdDt; import ca.uhn.fhir.model.primitive.IdDt;
@ -70,6 +72,6 @@ public @interface DeleteTags {
* , this method is expected to return a TagList containing only tags which * , this method is expected to return a TagList containing only tags which
* are specific to the given resource type. * are specific to the given resource type.
*/ */
Class<? extends IResource> type() default IResource.class; Class<? extends IBaseResource> type() default IBaseResource.class;
} }

View File

@ -25,6 +25,8 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; import java.lang.annotation.Target;
import org.hl7.fhir.instance.model.api.IBaseResource;
import ca.uhn.fhir.model.api.IResource; import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.primitive.IdDt; import ca.uhn.fhir.model.primitive.IdDt;
@ -78,6 +80,6 @@ public @interface GetTags {
* , this method is expected to return a TagList containing only tags which * , this method is expected to return a TagList containing only tags which
* are specific to the given resource type. * are specific to the given resource type.
*/ */
Class<? extends IResource> type() default IResource.class; Class<? extends IBaseResource> type() default IBaseResource.class;
} }

View File

@ -25,6 +25,8 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; import java.lang.annotation.Target;
import org.hl7.fhir.instance.model.api.IBaseResource;
import ca.uhn.fhir.model.api.IResource; import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.primitive.IdDt; import ca.uhn.fhir.model.primitive.IdDt;
//import ca.uhn.fhir.testmodel.Patient; // TODO: qualify this correctly //import ca.uhn.fhir.testmodel.Patient; // TODO: qualify this correctly
@ -77,6 +79,6 @@ public @interface History {
* The resource type that this method applies to. See the {@link History History annotation type documentation} * The resource type that this method applies to. See the {@link History History annotation type documentation}
* for information on usage patterns. * for information on usage patterns.
*/ */
Class<? extends IResource> type() default IResource.class; Class<? extends IBaseResource> type() default IBaseResource.class;
} }

View File

@ -31,7 +31,6 @@ import org.hl7.fhir.instance.model.api.IBaseResource;
import ca.uhn.fhir.context.ConfigurationException; import ca.uhn.fhir.context.ConfigurationException;
import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.api.TagList; import ca.uhn.fhir.model.api.TagList;
import ca.uhn.fhir.model.primitive.IdDt; import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.parser.IParser; import ca.uhn.fhir.parser.IParser;
@ -40,12 +39,8 @@ import ca.uhn.fhir.rest.annotation.TagListParam;
import ca.uhn.fhir.rest.api.RequestTypeEnum; import ca.uhn.fhir.rest.api.RequestTypeEnum;
import ca.uhn.fhir.rest.api.RestOperationTypeEnum; import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
import ca.uhn.fhir.rest.client.BaseHttpClientInvocation; import ca.uhn.fhir.rest.client.BaseHttpClientInvocation;
import ca.uhn.fhir.rest.server.Constants; import ca.uhn.fhir.rest.server.*;
import ca.uhn.fhir.rest.server.IResourceProvider; import ca.uhn.fhir.rest.server.exceptions.*;
import ca.uhn.fhir.rest.server.IRestfulServer;
import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor; import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
abstract class BaseAddOrDeleteTagsMethodBinding extends BaseMethodBinding<Void> { abstract class BaseAddOrDeleteTagsMethodBinding extends BaseMethodBinding<Void> {
@ -56,7 +51,7 @@ abstract class BaseAddOrDeleteTagsMethodBinding extends BaseMethodBinding<Void>
private String myResourceName; private String myResourceName;
private Integer myTagListParamIndex; private Integer myTagListParamIndex;
public BaseAddOrDeleteTagsMethodBinding(Method theMethod, FhirContext theContext, Object theProvider, Class<? extends IResource> theTypeFromMethodAnnotation) { public BaseAddOrDeleteTagsMethodBinding(Method theMethod, FhirContext theContext, Object theProvider, Class<? extends IBaseResource> theTypeFromMethodAnnotation) {
super(theMethod, theContext, theProvider); super(theMethod, theContext, theProvider);
if (theProvider instanceof IResourceProvider) { if (theProvider instanceof IResourceProvider) {

View File

@ -35,15 +35,11 @@ import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.IResource; import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum; import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
import ca.uhn.fhir.model.primitive.IdDt; import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.model.primitive.InstantDt;
import ca.uhn.fhir.model.valueset.BundleTypeEnum; import ca.uhn.fhir.model.valueset.BundleTypeEnum;
import ca.uhn.fhir.rest.annotation.History; import ca.uhn.fhir.rest.annotation.History;
import ca.uhn.fhir.rest.api.RestOperationTypeEnum; import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
import ca.uhn.fhir.rest.client.BaseHttpClientInvocation; import ca.uhn.fhir.rest.client.BaseHttpClientInvocation;
import ca.uhn.fhir.rest.server.Constants; import ca.uhn.fhir.rest.server.*;
import ca.uhn.fhir.rest.server.IBundleProvider;
import ca.uhn.fhir.rest.server.IResourceProvider;
import ca.uhn.fhir.rest.server.IRestfulServer;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
@ -79,7 +75,7 @@ public class HistoryMethodBinding extends BaseResourceReturningMethodBinding {
} }
} }
if (type != IResource.class) { if (type != IBaseResource.class && type != IResource.class) {
myResourceName = theContext.getResourceDefinition(type).getName(); myResourceName = theContext.getResourceDefinition(type).getName();
} else { } else {
myResourceName = null; myResourceName = null;
@ -245,8 +241,8 @@ public class HistoryMethodBinding extends BaseResourceReturningMethodBinding {
return ((IResourceProvider) theProvider).getResourceType(); return ((IResourceProvider) theProvider).getResourceType();
} }
History historyAnnotation = theMethod.getAnnotation(History.class); History historyAnnotation = theMethod.getAnnotation(History.class);
Class<? extends IResource> type = historyAnnotation.type(); Class<? extends IBaseResource> type = historyAnnotation.type();
if (type != IResource.class) { if (type != IBaseResource.class && type != IResource.class) {
return type; return type;
} }
return null; return null;

View File

@ -254,13 +254,16 @@
Prev Page Prev Page
</button> </button>
<script type="text/javascript" th:inline="javascript"> <script type="text/javascript" th:inline="javascript">
if ([[${riBundle.getLink('prev') == null}]]) { if ([[${riBundle.getLink('prev') == null && riBundle.getLink('previous') == null}]]) {
$('#page-prev-btn').prop('disabled', true); $('#page-prev-btn').prop('disabled', true);
} }
$('#page-prev-btn').click(function() { $('#page-prev-btn').click(function() {
var btn = $(this); var btn = $(this);
handleActionButtonClick($(this)); handleActionButtonClick($(this));
btn.append($('<input />', { type: 'hidden', name: 'page-url', value: [[${riBundle.getLinkOrCreate('prev').url}]] })); var prev = [[${riBundle.getLinkOrCreate('prev').url}]];
var previous = [[${riBundle.getLinkOrCreate('previous').url}]];
var url = prev != null ? prev : previous;
btn.append($('<input />', { type: 'hidden', name: 'page-url', value: url }));
$("#outerForm").attr("action", "page").submit(); $("#outerForm").attr("action", "page").submit();
}); });

View File

@ -78,6 +78,10 @@
<action type="add"> <action type="add">
CLI now defaults to DSTU3 mode if no FHIR version is specified CLI now defaults to DSTU3 mode if no FHIR version is specified
</action> </action>
<action type="add">
Server and annotation-client @History annotation now allows DSTU3+ resource
types in the type= property
</action>
</release> </release>
<release version="2.4" date="2017-04-19"> <release version="2.4" date="2017-04-19">
<action type="add"> <action type="add">