Merge branch 'master' into windows-fixes

# Conflicts:
#	hapi-fhir-jpaserver-subscription/src/main/java/ca/uhn/fhir/jpa/subscription/module/subscriber/SubscriptionDeliveringRestHookSubscriber.java
This commit is contained in:
Ken Stevens 2019-01-23 17:16:08 -05:00
commit cdd75bbe3a
10 changed files with 166 additions and 115 deletions

View File

@ -64,7 +64,7 @@ public class SubscriptionCanonicalizer<S extends IBaseResource> {
} }
} }
protected CanonicalSubscription canonicalizeDstu2(IBaseResource theSubscription) { private CanonicalSubscription canonicalizeDstu2(IBaseResource theSubscription) {
ca.uhn.fhir.model.dstu2.resource.Subscription subscription = (ca.uhn.fhir.model.dstu2.resource.Subscription) theSubscription; ca.uhn.fhir.model.dstu2.resource.Subscription subscription = (ca.uhn.fhir.model.dstu2.resource.Subscription) theSubscription;
CanonicalSubscription retVal = new CanonicalSubscription(); CanonicalSubscription retVal = new CanonicalSubscription();
@ -83,7 +83,7 @@ public class SubscriptionCanonicalizer<S extends IBaseResource> {
return retVal; return retVal;
} }
protected CanonicalSubscription canonicalizeDstu3(IBaseResource theSubscription) { private CanonicalSubscription canonicalizeDstu3(IBaseResource theSubscription) {
org.hl7.fhir.dstu3.model.Subscription subscription = (org.hl7.fhir.dstu3.model.Subscription) theSubscription; org.hl7.fhir.dstu3.model.Subscription subscription = (org.hl7.fhir.dstu3.model.Subscription) theSubscription;
CanonicalSubscription retVal = new CanonicalSubscription(); CanonicalSubscription retVal = new CanonicalSubscription();
@ -217,7 +217,7 @@ public class SubscriptionCanonicalizer<S extends IBaseResource> {
return null; return null;
} }
protected CanonicalSubscription canonicalizeR4(IBaseResource theSubscription) { private CanonicalSubscription canonicalizeR4(IBaseResource theSubscription) {
org.hl7.fhir.r4.model.Subscription subscription = (org.hl7.fhir.r4.model.Subscription) theSubscription; org.hl7.fhir.r4.model.Subscription subscription = (org.hl7.fhir.r4.model.Subscription) theSubscription;
CanonicalSubscription retVal = new CanonicalSubscription(); CanonicalSubscription retVal = new CanonicalSubscription();

View File

@ -20,6 +20,7 @@ package ca.uhn.fhir.jpa.subscription.module.matcher;
* #L% * #L%
*/ */
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.RuntimeResourceDefinition; import ca.uhn.fhir.context.RuntimeResourceDefinition;
import ca.uhn.fhir.context.RuntimeSearchParam; import ca.uhn.fhir.context.RuntimeSearchParam;
import ca.uhn.fhir.jpa.searchparam.MatchUrlService; import ca.uhn.fhir.jpa.searchparam.MatchUrlService;
@ -30,8 +31,11 @@ import ca.uhn.fhir.model.api.IQueryParameterType;
import ca.uhn.fhir.rest.api.Constants; import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.param.BaseParamWithPrefix; import ca.uhn.fhir.rest.param.BaseParamWithPrefix;
import ca.uhn.fhir.rest.param.ReferenceParam; import ca.uhn.fhir.rest.param.ReferenceParam;
import ca.uhn.fhir.rest.param.StringParam;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import org.hl7.fhir.instance.model.api.IAnyResource; import org.hl7.fhir.instance.model.api.IAnyResource;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@ -42,16 +46,18 @@ import java.util.function.Predicate;
@Service @Service
public class CriteriaResourceMatcher { public class CriteriaResourceMatcher {
public static final String CRITERIA = "CRITERIA"; private static final String CRITERIA = "CRITERIA";
@Autowired @Autowired
private MatchUrlService myMatchUrlService; private MatchUrlService myMatchUrlService;
@Autowired @Autowired
ISearchParamRegistry mySearchParamRegistry; ISearchParamRegistry mySearchParamRegistry;
@Autowired
FhirContext myFhirContext;
public SubscriptionMatchResult match(String theCriteria, RuntimeResourceDefinition theResourceDefinition, ResourceIndexedSearchParams theSearchParams) { public SubscriptionMatchResult match(String theCriteria, IBaseResource theResource, ResourceIndexedSearchParams theSearchParams) {
SearchParameterMap searchParameterMap; SearchParameterMap searchParameterMap;
try { try {
searchParameterMap = myMatchUrlService.translateMatchUrl(theCriteria, theResourceDefinition); searchParameterMap = myMatchUrlService.translateMatchUrl(theCriteria, myFhirContext.getResourceDefinition(theResource));
} catch (UnsupportedOperationException e) { } catch (UnsupportedOperationException e) {
return new SubscriptionMatchResult(theCriteria, CRITERIA); return new SubscriptionMatchResult(theCriteria, CRITERIA);
} }
@ -63,7 +69,7 @@ public class CriteriaResourceMatcher {
for (Map.Entry<String, List<List<? extends IQueryParameterType>>> entry : searchParameterMap.entrySet()) { for (Map.Entry<String, List<List<? extends IQueryParameterType>>> entry : searchParameterMap.entrySet()) {
String theParamName = entry.getKey(); String theParamName = entry.getKey();
List<List<? extends IQueryParameterType>> theAndOrParams = entry.getValue(); List<List<? extends IQueryParameterType>> theAndOrParams = entry.getValue();
SubscriptionMatchResult result = matchIdsWithAndOr(theParamName, theAndOrParams, theResourceDefinition, theSearchParams); SubscriptionMatchResult result = matchIdsWithAndOr(theParamName, theAndOrParams, theResource, theSearchParams);
if (!result.matched()){ if (!result.matched()){
return result; return result;
} }
@ -72,7 +78,7 @@ public class CriteriaResourceMatcher {
} }
// This method is modelled from SearchBuilder.searchForIdsWithAndOr() // This method is modelled from SearchBuilder.searchForIdsWithAndOr()
private SubscriptionMatchResult matchIdsWithAndOr(String theParamName, List<List<? extends IQueryParameterType>> theAndOrParams, RuntimeResourceDefinition theResourceDefinition, ResourceIndexedSearchParams theSearchParams) { private SubscriptionMatchResult matchIdsWithAndOr(String theParamName, List<List<? extends IQueryParameterType>> theAndOrParams, IBaseResource theResource, ResourceIndexedSearchParams theSearchParams) {
if (theAndOrParams.isEmpty()) { if (theAndOrParams.isEmpty()) {
return new SubscriptionMatchResult(true, CRITERIA); return new SubscriptionMatchResult(true, CRITERIA);
} }
@ -90,30 +96,44 @@ public class CriteriaResourceMatcher {
if (hasChain(theAndOrParams)) { if (hasChain(theAndOrParams)) {
return new SubscriptionMatchResult(theParamName, "Chained references are not supported"); return new SubscriptionMatchResult(theParamName, "Chained references are not supported");
} }
if (theParamName.equals(IAnyResource.SP_RES_ID)) { switch (theParamName) {
case IAnyResource.SP_RES_ID:
return new SubscriptionMatchResult(theParamName, CRITERIA); return new SubscriptionMatchResult(matchIdsAndOr(theAndOrParams, theResource), CRITERIA);
} else if (theParamName.equals(IAnyResource.SP_RES_LANGUAGE)) { case IAnyResource.SP_RES_LANGUAGE:
return new SubscriptionMatchResult(theParamName, CRITERIA); return new SubscriptionMatchResult(theParamName, CRITERIA);
} else if (theParamName.equals(Constants.PARAM_HAS)) { case Constants.PARAM_HAS:
return new SubscriptionMatchResult(theParamName, CRITERIA); return new SubscriptionMatchResult(theParamName, CRITERIA);
} else if (theParamName.equals(Constants.PARAM_TAG) || theParamName.equals(Constants.PARAM_PROFILE) || theParamName.equals(Constants.PARAM_SECURITY)) { case Constants.PARAM_TAG:
case Constants.PARAM_PROFILE:
case Constants.PARAM_SECURITY:
return new SubscriptionMatchResult(theParamName, CRITERIA); return new SubscriptionMatchResult(theParamName, CRITERIA);
} else { default:
String resourceName = theResourceDefinition.getName(); String resourceName = myFhirContext.getResourceDefinition(theResource).getName();
RuntimeSearchParam paramDef = mySearchParamRegistry.getActiveSearchParam(resourceName, theParamName); RuntimeSearchParam paramDef = mySearchParamRegistry.getActiveSearchParam(resourceName, theParamName);
return matchResourceParam(theParamName, theAndOrParams, theSearchParams, resourceName, paramDef); return matchResourceParam(theParamName, theAndOrParams, theSearchParams, resourceName, paramDef);
} }
} }
private boolean matchIdsAndOr(List<List<? extends IQueryParameterType>> theAndOrParams, IBaseResource theResource) {
return theAndOrParams.stream().allMatch(nextAnd -> matchIdsOr(nextAnd, theResource));
}
private boolean matchIdsOr(List<? extends IQueryParameterType> theOrParams, IBaseResource theResource) {
return theOrParams.stream().anyMatch(param -> param instanceof StringParam && matchId(((StringParam)param).getValue(), theResource.getIdElement()));
}
private boolean matchId(String theValue, IIdType theId) {
return theValue.equals(theId.getValue()) || theValue.equals(theId.getIdPart());
}
private SubscriptionMatchResult matchResourceParam(String theParamName, List<List<? extends IQueryParameterType>> theAndOrParams, ResourceIndexedSearchParams theSearchParams, String theResourceName, RuntimeSearchParam theParamDef) { private SubscriptionMatchResult matchResourceParam(String theParamName, List<List<? extends IQueryParameterType>> theAndOrParams, ResourceIndexedSearchParams theSearchParams, String theResourceName, RuntimeSearchParam theParamDef) {
if (theParamDef != null) { if (theParamDef != null) {
switch (theParamDef.getParamType()) { switch (theParamDef.getParamType()) {

View File

@ -21,7 +21,6 @@ package ca.uhn.fhir.jpa.subscription.module.matcher;
*/ */
import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.RuntimeResourceDefinition;
import ca.uhn.fhir.jpa.model.entity.ResourceTable; import ca.uhn.fhir.jpa.model.entity.ResourceTable;
import ca.uhn.fhir.jpa.searchparam.extractor.ResourceIndexedSearchParams; import ca.uhn.fhir.jpa.searchparam.extractor.ResourceIndexedSearchParams;
import ca.uhn.fhir.jpa.searchparam.extractor.ResourceLinkExtractor; import ca.uhn.fhir.jpa.searchparam.extractor.ResourceLinkExtractor;
@ -61,7 +60,6 @@ public class InMemorySubscriptionMatcher implements ISubscriptionMatcher {
ResourceIndexedSearchParams searchParams = new ResourceIndexedSearchParams(); ResourceIndexedSearchParams searchParams = new ResourceIndexedSearchParams();
mySearchParamExtractorService.extractFromResource(searchParams, entity, resource); mySearchParamExtractorService.extractFromResource(searchParams, entity, resource);
myResourceLinkExtractor.extractResourceLinks(searchParams, entity, resource, resource.getMeta().getLastUpdated(), myInlineResourceLinkResolver); myResourceLinkExtractor.extractResourceLinks(searchParams, entity, resource, resource.getMeta().getLastUpdated(), myInlineResourceLinkResolver);
RuntimeResourceDefinition resourceDefinition = myContext.getResourceDefinition(resource); return myCriteriaResourceMatcher.match(criteria, resource, searchParams);
return myCriteriaResourceMatcher.match(criteria, resourceDefinition, searchParams);
} }
} }

View File

@ -101,7 +101,8 @@ public class SubscriptionDeliveringRestHookSubscriber extends BaseSubscriptionDe
try { try {
operation.execute(); operation.execute();
} catch (ResourceNotFoundException e) { } catch (ResourceNotFoundException e) {
ourLog.error("Cannot reach " + theMsg.getSubscription().getEndpointUrl(), e); ourLog.error("Cannot reach {} ", theMsg.getSubscription().getEndpointUrl());
ourLog.error("Exception: ", e);
throw e; throw e;
} }
} }

View File

@ -12,6 +12,7 @@ import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections;
import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
@ -39,7 +40,6 @@ public class InMemorySubscriptionMatcherTestR3 extends BaseSubscriptionDstu3Test
} }
@Test @Test
@Ignore
public void testResourceById() { public void testResourceById() {
ProcedureRequest pr = new ProcedureRequest(); ProcedureRequest pr = new ProcedureRequest();
@ -47,12 +47,12 @@ public class InMemorySubscriptionMatcherTestR3 extends BaseSubscriptionDstu3Test
pr.setIntent(ProcedureRequest.ProcedureRequestIntent.ORIGINALORDER); pr.setIntent(ProcedureRequest.ProcedureRequestIntent.ORIGINALORDER);
assertMatched(pr, "ProcedureRequest?_id=123"); assertMatched(pr, "ProcedureRequest?_id=123");
assertMatched(pr, "ProcedureRequest?_id=Patient/123"); assertMatched(pr, "ProcedureRequest?_id=ProcedureRequest/123");
assertMatched(pr, "ProcedureRequest?_id=Patient/123,Patient/999"); assertMatched(pr, "ProcedureRequest?_id=ProcedureRequest/123,ProcedureRequest/999");
assertMatched(pr, "ProcedureRequest?_id=Patient/123&_id=Patient/123"); assertMatched(pr, "ProcedureRequest?_id=ProcedureRequest/123&_id=ProcedureRequest/123");
assertNotMatched(pr, "ProcedureRequest?_id=Patient/888"); assertNotMatched(pr, "ProcedureRequest?_id=ProcedureRequest/888");
assertNotMatched(pr, "ProcedureRequest?_id=Patient/888,Patient/999"); assertNotMatched(pr, "ProcedureRequest?_id=ProcedureRequest/888,ProcedureRequest/999");
assertNotMatched(pr, "ProcedureRequest?_id=Patient/123&_id=Patient/888"); assertNotMatched(pr, "ProcedureRequest?_id=ProcedureRequest/123&_id=ProcedureRequest/888");
} }
@ -301,7 +301,7 @@ public class InMemorySubscriptionMatcherTestR3 extends BaseSubscriptionDstu3Test
sp.setXpathUsage(SearchParameter.XPathUsageType.NORMAL); sp.setXpathUsage(SearchParameter.XPathUsageType.NORMAL);
sp.setStatus(Enumerations.PublicationStatus.ACTIVE); sp.setStatus(Enumerations.PublicationStatus.ACTIVE);
IBundleProvider bundle = new SimpleBundleProvider(Arrays.asList(sp), "uuid"); IBundleProvider bundle = new SimpleBundleProvider(Collections.singletonList(sp), "uuid");
initSearchParamRegistry(bundle); initSearchParamRegistry(bundle);
{ {
@ -333,7 +333,7 @@ public class InMemorySubscriptionMatcherTestR3 extends BaseSubscriptionDstu3Test
sp.setXpathUsage(SearchParameter.XPathUsageType.NORMAL); sp.setXpathUsage(SearchParameter.XPathUsageType.NORMAL);
sp.setStatus(Enumerations.PublicationStatus.ACTIVE); sp.setStatus(Enumerations.PublicationStatus.ACTIVE);
IBundleProvider bundle = new SimpleBundleProvider(Arrays.asList(sp), "uuid"); IBundleProvider bundle = new SimpleBundleProvider(Collections.singletonList(sp), "uuid");
initSearchParamRegistry(bundle); initSearchParamRegistry(bundle);
{ {
@ -425,7 +425,7 @@ public class InMemorySubscriptionMatcherTestR3 extends BaseSubscriptionDstu3Test
sp.setXpathUsage(SearchParameter.XPathUsageType.NORMAL); sp.setXpathUsage(SearchParameter.XPathUsageType.NORMAL);
sp.setStatus(Enumerations.PublicationStatus.ACTIVE); sp.setStatus(Enumerations.PublicationStatus.ACTIVE);
IBundleProvider bundle = new SimpleBundleProvider(Arrays.asList(sp), "uuid"); IBundleProvider bundle = new SimpleBundleProvider(Collections.singletonList(sp), "uuid");
initSearchParamRegistry(bundle); initSearchParamRegistry(bundle);
{ {

View File

@ -35,7 +35,7 @@ import ca.uhn.fhir.model.api.annotation.DatatypeDef;
/** /**
* Primitive type "base64Binary" in FHIR: a sequence of bytes represented in base64 * Primitive type "base64Binary" in FHIR: a sequence of bytes represented in base64
*/ */
@DatatypeDef(name = "base64binary") @DatatypeDef(name = "base64Binary")
public class Base64BinaryType extends PrimitiveType<byte[]> { public class Base64BinaryType extends PrimitiveType<byte[]> {
private static final long serialVersionUID = 3L; private static final long serialVersionUID = 3L;

View File

@ -46,7 +46,13 @@ public class ModelDstu3Test {
@Test @Test
public void testSetters() { public void testSetters() {
Claim claim = new Claim(); Claim claim = new Claim();
claim.setIdentifier(new ArrayList<Identifier>()).setCareTeam(new ArrayList<CareTeamComponent>()); claim.setIdentifier(new ArrayList<>()).setCareTeam(new ArrayList<>());
}
@Test
public void testbase64BinaryName() {
assertEquals("base64Binary", ourCtx.getElementDefinition("base64binary").getName());
assertEquals("base64Binary", ourCtx.getElementDefinition("base64Binary").getName());
} }
@Test @Test

View File

@ -1,78 +1,78 @@
/* /*
Copyright (c) 2011+, HL7, Inc Copyright (c) 2011+, HL7, Inc
All rights reserved. All rights reserved.
Redistribution and use in source and binary forms, with or without modification, Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met: are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this * Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer. list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, * Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution. and/or other materials provided with the distribution.
* Neither the name of HL7 nor the names of its contributors may be used to * Neither the name of HL7 nor the names of its contributors may be used to
endorse or promote products derived from this software without specific endorse or promote products derived from this software without specific
prior written permission. prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE. POSSIBILITY OF SUCH DAMAGE.
*/ */
package org.hl7.fhir.r4.model; package org.hl7.fhir.r4.model;
import org.apache.commons.codec.binary.Base64; import org.apache.commons.codec.binary.Base64;
import ca.uhn.fhir.model.api.annotation.DatatypeDef; import ca.uhn.fhir.model.api.annotation.DatatypeDef;
/** /**
* Primitive type "base64Binary" in FHIR: a sequence of bytes represented in base64 * Primitive type "base64Binary" in FHIR: a sequence of bytes represented in base64
*/ */
@DatatypeDef(name="base64binary") @DatatypeDef(name="base64Binary")
public class Base64BinaryType extends PrimitiveType<byte[]> { public class Base64BinaryType extends PrimitiveType<byte[]> {
private static final long serialVersionUID = 3L; private static final long serialVersionUID = 3L;
/** /**
* Constructor * Constructor
*/ */
public Base64BinaryType() { public Base64BinaryType() {
super(); super();
} }
public Base64BinaryType(byte[] theBytes) { public Base64BinaryType(byte[] theBytes) {
super(); super();
setValue(theBytes); setValue(theBytes);
} }
public Base64BinaryType(String theValue) { public Base64BinaryType(String theValue) {
super(); super();
setValueAsString(theValue); setValueAsString(theValue);
} }
protected byte[] parse(String theValue) { protected byte[] parse(String theValue) {
return Base64.decodeBase64(theValue); return Base64.decodeBase64(theValue);
} }
protected String encode(byte[] theValue) { protected String encode(byte[] theValue) {
return Base64.encodeBase64String(theValue); return Base64.encodeBase64String(theValue);
} }
@Override @Override
public Base64BinaryType copy() { public Base64BinaryType copy() {
Base64BinaryType ret = new Base64BinaryType(getValue()); Base64BinaryType ret = new Base64BinaryType(getValue());
copyValues(ret); copyValues(ret);
return ret; return ret;
} }
public String fhirType() { public String fhirType() {
return "base64Binary"; return "base64Binary";
} }
} }

View File

@ -0,0 +1,19 @@
package org.hl7.fhir.r4.model;
import ca.uhn.fhir.context.FhirContext;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
public class ModelR4Test {
private static FhirContext ourCtx = FhirContext.forR4();
@Test
public void testbase64BinaryName() {
assertEquals("base64Binary", ourCtx.getElementDefinition("base64binary").getName());
assertEquals("base64Binary", ourCtx.getElementDefinition("base64Binary").getName());
}
}

View File

@ -19,7 +19,7 @@
<ul> <ul>
<li>Spring (JPA): 5.0.8.RELEASE -&gt; 5.1.3.RELEASE</li> <li>Spring (JPA): 5.0.8.RELEASE -&gt; 5.1.3.RELEASE</li>
<li>Spring-Data (JPA): 2.0.7.RELEASE -&gt; 2.1.3.RELEASE</li> <li>Spring-Data (JPA): 2.0.7.RELEASE -&gt; 2.1.3.RELEASE</li>
<li>Hibernate-Core (JPA): 5.3.6.FINAL -&gt; 5.4.0.FINAL</li> <li>Hibernate-Core (JPA): 5.3.6.FINAL -&gt; 5.4.1.FINAL</li>
<li>Hibernate-Search (JPA): 5.10.3.FINAL -&gt; 5.11.0.FINAL</li> <li>Hibernate-Search (JPA): 5.10.3.FINAL -&gt; 5.11.0.FINAL</li>
<li>Thymeleaf (JPA): 3.0.9.RELEASE -&gt; 3.0.11.RELEASE</li> <li>Thymeleaf (JPA): 3.0.9.RELEASE -&gt; 3.0.11.RELEASE</li>
<li>thymeleaf-spring4 (Testpage Overlay) has been replaced with thymeleaf-spring5</li> <li>thymeleaf-spring4 (Testpage Overlay) has been replaced with thymeleaf-spring5</li>
@ -320,6 +320,13 @@
result in the 10th result being returned). This will now result in an empty result in the 10th result being returned). This will now result in an empty
response Bundle as would be expected. response Bundle as would be expected.
</action> </action>
<action type="add">
Added support for _id in in-memory matcher
</action>
<action type="fix">
The casing of the base64Binary datatype was incorrect in the DSTU3 and R4 model classes.
This has been corrected.
</action>
</release> </release>
<release version="3.6.0" date="2018-11-12" description="Food"> <release version="3.6.0" date="2018-11-12" description="Food">
<action type="add"> <action type="add">