diff --git a/hapi-fhir-android/pom.xml b/hapi-fhir-android/pom.xml
index 3bc12274ac0..0f7f5a7c60e 100644
--- a/hapi-fhir-android/pom.xml
+++ b/hapi-fhir-android/pom.xml
@@ -56,6 +56,12 @@
org.slf4j
slf4j-android
+
+ net.sourceforge.cobertura
+ cobertura
+ 2.1.1
+ true
+
org.slf4j
slf4j-api
@@ -74,7 +80,11 @@
+ requires it.
+
+ We provide a dummy implementation of servlet api to reduce size
+ and prevent from rewriting the BaseMethodBinding and friends.
+ -->
javax.servlet
javax.servlet-api
@@ -120,138 +130,134 @@
org.apache.maven.plugins
maven-shade-plugin
2.3
+
+ true
+ true
+ true
+
+
+ ca.uhn.hapi.fhir:hapi-fhir-base
+ org.glassfish:javax.json
+ org.codehaus.woodstox:woodstox-core-asl
+ javax.xml.stream:stax-api
+ org.codehaus.woodstox:stax2-api
+ org.glassfish:javax.json
+ net.sourceforge.cobertura:cobertura
+
+ javax.servlet:javax.servlet-api
+
+
+
+
+ javax.xml.stream
+ ca.uhn.fhir.repackage.javax.xml.stream
+
+
+ javax.json
+ ca.uhn.fhir.repackage.javax.json
+
+
+
+
+
+ net.sourceforge.cobertura:cobertura
+
+ net/sourceforge/cobertura/CoverageIgnore*
+
+
+
+
+ ca.uhn.hapi.fhir:hapi-fhir-base
+
+
+ ca/uhn/fhir/util/ITestingUiClientFactory
+
+
+
+ ca/uhn/fhir/validation/schematron/SchematronBaseValidator*
+
+ ca/uhn/fhir/narrative/*Thymeleaf*
+
+
+
+
+
- normal
- package
-
- shade
-
-
- true
- true
- true
-
-
- ca.uhn.hapi.fhir:hapi-fhir-base
- org.glassfish:javax.json
- org.codehaus.woodstox:woodstox-core-asl
- javax.xml.stream:stax-api
- org.codehaus.woodstox:stax2-api
- org.glassfish:javax.json
-
-
-
-
- javax.xml.stream
- ca.uhn.fhir.repackage.javax.xml.stream
-
-
- javax.json
- ca.uhn.fhir.repackage.javax.json
-
-
-
-
- ca.uhn.hapi.fhir:hapi-fhir-base
-
- **/*.java
-
-
-
-
-
+ shaded
+ package
+
+ shade
+
+
+
dstu
- package
-
- shade
-
+ package
+
+ shade
+
- true
- true
- true
dstu
-
- ca.uhn.hapi.fhir:hapi-fhir-base
ca.uhn.hapi.fhir:hapi-fhir-structures-dstu
- org.glassfish:javax.json
- org.codehaus.woodstox:woodstox-core-asl
- javax.xml.stream:stax-api
-
- org.codehaus.woodstox:stax2-api
-
-
- org.glassfish:javax.json
-
-
- javax.xml.stream
- ca.uhn.fhir.repackage.javax.xml.stream
-
-
- javax.json
- ca.uhn.fhir.repackage.javax.json
-
-
-
+
+
+
dstu2
- package
-
- shade
-
+ package
+
+ shade
+
- true
- true
- true
dstu2
-
- ca.uhn.hapi.fhir:hapi-fhir-base
ca.uhn.hapi.fhir:hapi-fhir-structures-dstu2
- org.glassfish:javax.json
- org.codehaus.woodstox:woodstox-core-asl
- javax.xml.stream:stax-api
-
- org.codehaus.woodstox:stax2-api
-
- org.glassfish:javax.json
-
-
- javax.xml.stream
- ca.uhn.fhir.repackage.javax.xml.stream
-
-
- javax.json
- ca.uhn.fhir.repackage.javax.json
-
-
+
+
diff --git a/hapi-fhir-base/pom.xml b/hapi-fhir-base/pom.xml
index 72051e0877f..949f1bda8ec 100644
--- a/hapi-fhir-base/pom.xml
+++ b/hapi-fhir-base/pom.xml
@@ -132,6 +132,20 @@
+
+
+ org.apache.maven.plugins
+ maven-source-plugin
+
+
+ attach-sources
+
+ jar
+
+
+
+
+
src/main/resources
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/BeanUtils.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/BeanUtils.java
index 6e8b9b18495..03b86d86aee 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/BeanUtils.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/BeanUtils.java
@@ -20,49 +20,37 @@ package ca.uhn.fhir.util;
* #L%
*/
-import java.beans.BeanInfo;
-import java.beans.IntrospectionException;
-import java.beans.Introspector;
-import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
+import ca.uhn.fhir.util.reflection.IBeanUtils;
+
public class BeanUtils {
- public static Method findAccessor(Class> theClassToIntrospect, Class> theTargetReturnType, String thePropertyName) throws NoSuchFieldException {
- BeanInfo info;
- try {
- info = Introspector.getBeanInfo(theClassToIntrospect);
- } catch (IntrospectionException e) {
- throw new NoSuchFieldException(e.getMessage());
- }
- for (PropertyDescriptor pd : info.getPropertyDescriptors()) {
- if (thePropertyName.equals(pd.getName())) {
- if (theTargetReturnType.isAssignableFrom(pd.getPropertyType())) {
- return pd.getReadMethod();
- }else {
- throw new NoSuchFieldException(theClassToIntrospect + " has an accessor for field " + thePropertyName + " but it does not return type " + theTargetReturnType);
+ private static IBeanUtils beanUtils;
+
+ private static IBeanUtils getBeanUtils() {
+ if (beanUtils == null) {
+ try {
+ beanUtils = (IBeanUtils) Class.forName("ca.uhn.fhir.util.reflection.JavaBeansBeanUtil").newInstance();
+ } catch (ReflectiveOperationException e) {
+ try {
+ beanUtils = (IBeanUtils) Class.forName("ca.uhn.fhir.util.reflection.JavaReflectBeanUtil")
+ .newInstance();
+ } catch (ReflectiveOperationException e1) {
+ throw new RuntimeException("Could not resolve BeanUtil implementation");
}
}
}
- throw new NoSuchFieldException(theClassToIntrospect + " has no accessor for field " + thePropertyName);
+ return beanUtils;
}
- public static Method findMutator(Class> theClassToIntrospect, Class> theTargetReturnType, String thePropertyName) throws NoSuchFieldException {
- BeanInfo info;
- try {
- info = Introspector.getBeanInfo(theClassToIntrospect);
- } catch (IntrospectionException e) {
- throw new NoSuchFieldException(e.getMessage());
- }
- for (PropertyDescriptor pd : info.getPropertyDescriptors()) {
- if (thePropertyName.equals(pd.getName())) {
- if (theTargetReturnType.isAssignableFrom(pd.getPropertyType())) {
- return pd.getWriteMethod();
- }else {
- throw new NoSuchFieldException(theClassToIntrospect + " has an mutator for field " + thePropertyName + " but it does not return type " + theTargetReturnType);
- }
- }
- }
- throw new NoSuchFieldException(theClassToIntrospect + " has no mutator for field " + thePropertyName);
+ public static Method findAccessor(Class> theClassToIntrospect, Class> theTargetReturnType, String thePropertyName)
+ throws NoSuchFieldException {
+ return getBeanUtils().findAccessor(theClassToIntrospect, theTargetReturnType, thePropertyName);
}
+
+ public static Method findMutator(Class> theClassToIntrospect, Class> theTargetReturnType, String thePropertyName)
+ throws NoSuchFieldException {
+ return getBeanUtils().findMutator(theClassToIntrospect, theTargetReturnType, thePropertyName);
+ }
}
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/ObjectUtil.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/ObjectUtil.java
index 70413d258c3..b1b6bcd678b 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/ObjectUtil.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/ObjectUtil.java
@@ -1,5 +1,7 @@
package ca.uhn.fhir.util;
+import org.apache.commons.lang3.StringUtils;
+
/*
* #%L
* HAPI FHIR - Core Library
@@ -32,4 +34,16 @@ public class ObjectUtil {
return object1.equals(object2);
}
+ public static T requireNonNull(T obj, String message) {
+ if (obj == null)
+ throw new NullPointerException(message);
+ return obj;
+ }
+
+ public static void requireNotEmpty(String str, String message) {
+ if (StringUtils.isBlank(str)) {
+ throw new IllegalArgumentException(message);
+ }
+ }
+
}
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/XmlUtil.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/XmlUtil.java
index 5938389b912..fe6b26cd1e8 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/XmlUtil.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/XmlUtil.java
@@ -21,20 +21,15 @@ package ca.uhn.fhir.util;
*/
import java.io.IOException;
-import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
-import java.net.MalformedURLException;
-import java.net.URL;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
-import java.util.jar.Attributes;
-import java.util.jar.Manifest;
import javax.xml.stream.FactoryConfigurationError;
import javax.xml.stream.XMLEventReader;
@@ -52,18 +47,15 @@ import org.codehaus.stax2.io.EscapingWriterFactory;
import com.ctc.wstx.api.WstxInputProperties;
import com.ctc.wstx.stax.WstxOutputFactory;
+import ca.uhn.fhir.util.jar.DependencyLogFactory;
+import ca.uhn.fhir.util.jar.IDependencyLog;
+
/**
* Utility methods for working with the StAX API.
*
* This class contains code adapted from the Apache Axiom project.
*/
public class XmlUtil {
- private static final Attributes.Name BUNDLE_SYMBOLIC_NAME = new Attributes.Name("Bundle-SymbolicName");
- private static final Attributes.Name BUNDLE_VENDOR = new Attributes.Name("Bundle-Vendor");
- private static final Attributes.Name BUNDLE_VERSION = new Attributes.Name("Bundle-Version");
- private static final Attributes.Name IMPLEMENTATION_TITLE = new Attributes.Name("Implementation-Title");
- private static final Attributes.Name IMPLEMENTATION_VENDOR = new Attributes.Name("Implementation-Vendor");
- private static final Attributes.Name IMPLEMENTATION_VERSION = new Attributes.Name("Implementation-Version");
private static volatile boolean ourHaveLoggedStaxImplementation;
private static volatile XMLInputFactory ourInputFactory;
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(XmlUtil.class);
@@ -1645,73 +1637,12 @@ public class XmlUtil {
return outputFactory;
}
- private static URL getRootUrlForClass(Class> cls) {
- ClassLoader classLoader = cls.getClassLoader();
- String resource = cls.getName().replace('.', '/') + ".class";
- if (classLoader == null) {
- // A null class loader means the bootstrap class loader. In this case we use the
- // system class loader. This is safe since we can assume that the system class
- // loader uses parent first as delegation policy.
- classLoader = ClassLoader.getSystemClassLoader();
- }
- URL url = classLoader.getResource(resource);
- if (url == null) {
- return null;
- }
- String file = url.getFile();
- if (file.endsWith(resource)) {
- try {
- return new URL(url.getProtocol(), url.getHost(), url.getPort(), file.substring(0, file.length() - resource.length()));
- } catch (MalformedURLException ex) {
- return null;
- }
- } else {
- return null;
- }
- }
-
private static void logStaxImplementation(Class> theClass) {
- try {
- URL rootUrl = getRootUrlForClass(theClass);
- if (rootUrl == null) {
- ourLog.info("Unable to determine location of StAX implementation containing class");
- } else {
- Manifest manifest;
- URL metaInfUrl = new URL(rootUrl, "META-INF/MANIFEST.MF");
- InputStream is = metaInfUrl.openStream();
- try {
- manifest = new Manifest(is);
- } finally {
- is.close();
- }
- Attributes attrs = manifest.getMainAttributes();
- String title = attrs.getValue(IMPLEMENTATION_TITLE);
- String symbolicName = attrs.getValue(BUNDLE_SYMBOLIC_NAME);
- if (symbolicName != null) {
- int i = symbolicName.indexOf(';');
- if (i != -1) {
- symbolicName = symbolicName.substring(0, i);
- }
- }
- String vendor = attrs.getValue(IMPLEMENTATION_VENDOR);
- if (vendor == null) {
- vendor = attrs.getValue(BUNDLE_VENDOR);
- }
- String version = attrs.getValue(IMPLEMENTATION_VERSION);
- if (version == null) {
- version = attrs.getValue(BUNDLE_VERSION);
- }
- if (ourLog.isDebugEnabled()) {
- ourLog.debug("FHIR XML procesing will use StAX implementation at {}\n Title: {}\n Symbolic name: {}\n Vendor: {}\n Version: {}", new Object[] { rootUrl, title, symbolicName, vendor, version } );
- } else {
- ourLog.info("FHIR XML procesing will use StAX implementation '{}' version '{}'", title, version);
- }
- }
- } catch (Throwable e) {
- ourLog.info("Unable to determine StAX implementation: " + e.getMessage());
- } finally {
- ourHaveLoggedStaxImplementation = true;
+ IDependencyLog logger = DependencyLogFactory.createJarLogger();
+ if (logger != null) {
+ logger.logStaxImplementation(theClass);
}
+ ourHaveLoggedStaxImplementation = true;
}
public static void main(String[] args) throws FactoryConfigurationError, XMLStreamException {
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/jar/DependencyLogFactory.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/jar/DependencyLogFactory.java
new file mode 100644
index 00000000000..ea861a8254d
--- /dev/null
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/jar/DependencyLogFactory.java
@@ -0,0 +1,36 @@
+package ca.uhn.fhir.util.jar;
+
+/*
+ * #%L
+ * HAPI FHIR - Core Library
+ * %%
+ * Copyright (C) 2014 - 2015 University Health Network
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * #L%
+ */
+
+public class DependencyLogFactory {
+ private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(DependencyLogFactory.class);
+
+ @SuppressWarnings("unchecked")
+ public static IDependencyLog createJarLogger() {
+ try {
+ Class clas = (Class) Class.forName("ca.uhn.fhir.util.jar.DependencyLogImpl");
+ return clas.newInstance();
+ } catch (ReflectiveOperationException e) {
+ ourLog.info("Could not log dependency.");
+ return null;
+ }
+ }
+}
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/jar/DependencyLogImpl.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/jar/DependencyLogImpl.java
new file mode 100644
index 00000000000..b3c778073d5
--- /dev/null
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/jar/DependencyLogImpl.java
@@ -0,0 +1,107 @@
+package ca.uhn.fhir.util.jar;
+
+/*
+ * #%L
+ * HAPI FHIR - Core Library
+ * %%
+ * Copyright (C) 2014 - 2015 University Health Network
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * #L%
+ */
+
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.jar.Attributes;
+import java.util.jar.Manifest;
+
+import ca.uhn.fhir.util.XmlUtil;
+
+public class DependencyLogImpl implements IDependencyLog {
+ private static final Attributes.Name BUNDLE_SYMBOLIC_NAME = new Attributes.Name("Bundle-SymbolicName");
+ private static final Attributes.Name BUNDLE_VENDOR = new Attributes.Name("Bundle-Vendor");
+ private static final Attributes.Name BUNDLE_VERSION = new Attributes.Name("Bundle-Version");
+ private static final Attributes.Name IMPLEMENTATION_TITLE = new Attributes.Name("Implementation-Title");
+ private static final Attributes.Name IMPLEMENTATION_VENDOR = new Attributes.Name("Implementation-Vendor");
+ private static final Attributes.Name IMPLEMENTATION_VERSION = new Attributes.Name("Implementation-Version");
+ private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(XmlUtil.class);
+
+ @Override
+ public void logStaxImplementation(Class> theClass) {
+ try {
+ URL rootUrl = getRootUrlForClass(theClass);
+ if (rootUrl == null) {
+ ourLog.info("Unable to determine location of StAX implementation containing class");
+ } else {
+ Manifest manifest;
+ URL metaInfUrl = new URL(rootUrl, "META-INF/MANIFEST.MF");
+ InputStream is = metaInfUrl.openStream();
+ try {
+ manifest = new Manifest(is);
+ } finally {
+ is.close();
+ }
+ Attributes attrs = manifest.getMainAttributes();
+ String title = attrs.getValue(IMPLEMENTATION_TITLE);
+ String symbolicName = attrs.getValue(BUNDLE_SYMBOLIC_NAME);
+ if (symbolicName != null) {
+ int i = symbolicName.indexOf(';');
+ if (i != -1) {
+ symbolicName = symbolicName.substring(0, i);
+ }
+ }
+ String vendor = attrs.getValue(IMPLEMENTATION_VENDOR);
+ if (vendor == null) {
+ vendor = attrs.getValue(BUNDLE_VENDOR);
+ }
+ String version = attrs.getValue(IMPLEMENTATION_VERSION);
+ if (version == null) {
+ version = attrs.getValue(BUNDLE_VERSION);
+ }
+ if (ourLog.isDebugEnabled()) {
+ ourLog.debug("FHIR XML procesing will use StAX implementation at {}\n Title: {}\n Symbolic name: {}\n Vendor: {}\n Version: {}", new Object[] { rootUrl, title, symbolicName, vendor, version } );
+ } else {
+ ourLog.info("FHIR XML procesing will use StAX implementation '{}' version '{}'", title, version);
+ }
+ }
+ } catch (Throwable e) {
+ ourLog.info("Unable to determine StAX implementation: " + e.getMessage());
+ }
+ }
+
+ private static URL getRootUrlForClass(Class> cls) {
+ ClassLoader classLoader = cls.getClassLoader();
+ String resource = cls.getName().replace('.', '/') + ".class";
+ if (classLoader == null) {
+ // A null class loader means the bootstrap class loader. In this case we use the
+ // system class loader. This is safe since we can assume that the system class
+ // loader uses parent first as delegation policy.
+ classLoader = ClassLoader.getSystemClassLoader();
+ }
+ URL url = classLoader.getResource(resource);
+ if (url == null) {
+ return null;
+ }
+ String file = url.getFile();
+ if (file.endsWith(resource)) {
+ try {
+ return new URL(url.getProtocol(), url.getHost(), url.getPort(), file.substring(0, file.length() - resource.length()));
+ } catch (MalformedURLException ex) {
+ return null;
+ }
+ } else {
+ return null;
+ }
+ }
+}
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/jar/IDependencyLog.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/jar/IDependencyLog.java
new file mode 100644
index 00000000000..3ad25a542ed
--- /dev/null
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/jar/IDependencyLog.java
@@ -0,0 +1,27 @@
+package ca.uhn.fhir.util.jar;
+
+/*
+ * #%L
+ * HAPI FHIR - Core Library
+ * %%
+ * Copyright (C) 2014 - 2015 University Health Network
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * #L%
+ */
+
+public interface IDependencyLog {
+
+ void logStaxImplementation(Class> theClass);
+
+}
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/reflection/IBeanUtils.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/reflection/IBeanUtils.java
new file mode 100644
index 00000000000..36f1784c6f3
--- /dev/null
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/reflection/IBeanUtils.java
@@ -0,0 +1,31 @@
+package ca.uhn.fhir.util.reflection;
+
+import java.lang.reflect.Method;
+
+/*
+ * #%L
+ * HAPI FHIR - Core Library
+ * %%
+ * Copyright (C) 2014 - 2015 University Health Network
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * #L%
+ */
+
+public interface IBeanUtils {
+ Method findAccessor(Class> theClassToIntrospect, Class> theTargetReturnType, String thePropertyName)
+ throws NoSuchFieldException;
+
+ Method findMutator(Class> theClassToIntrospect, Class> theTargetReturnType, String thePropertyName)
+ throws NoSuchFieldException;
+}
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/reflection/JavaBeansBeanUtil.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/reflection/JavaBeansBeanUtil.java
new file mode 100644
index 00000000000..c7f43cd1106
--- /dev/null
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/reflection/JavaBeansBeanUtil.java
@@ -0,0 +1,70 @@
+package ca.uhn.fhir.util.reflection;
+
+/*
+ * #%L
+ * HAPI FHIR - Core Library
+ * %%
+ * Copyright (C) 2014 - 2015 University Health Network
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * #L%
+ */
+
+import java.beans.BeanInfo;
+import java.beans.IntrospectionException;
+import java.beans.Introspector;
+import java.beans.PropertyDescriptor;
+import java.lang.reflect.Method;
+
+public class JavaBeansBeanUtil implements IBeanUtils {
+
+ @Override
+ public Method findAccessor(Class> theClassToIntrospect, Class> theTargetReturnType, String thePropertyName) throws NoSuchFieldException {
+ BeanInfo info;
+ try {
+ info = Introspector.getBeanInfo(theClassToIntrospect);
+ } catch (IntrospectionException e) {
+ throw new NoSuchFieldException(e.getMessage());
+ }
+ for (PropertyDescriptor pd : info.getPropertyDescriptors()) {
+ if (thePropertyName.equals(pd.getName())) {
+ if (theTargetReturnType.isAssignableFrom(pd.getPropertyType())) {
+ return pd.getReadMethod();
+ }else {
+ throw new NoSuchFieldException(theClassToIntrospect + " has an accessor for field " + thePropertyName + " but it does not return type " + theTargetReturnType);
+ }
+ }
+ }
+ throw new NoSuchFieldException(theClassToIntrospect + " has no accessor for field " + thePropertyName);
+ }
+
+ @Override
+ public Method findMutator(Class> theClassToIntrospect, Class> theTargetReturnType, String thePropertyName) throws NoSuchFieldException {
+ BeanInfo info;
+ try {
+ info = Introspector.getBeanInfo(theClassToIntrospect);
+ } catch (IntrospectionException e) {
+ throw new NoSuchFieldException(e.getMessage());
+ }
+ for (PropertyDescriptor pd : info.getPropertyDescriptors()) {
+ if (thePropertyName.equals(pd.getName())) {
+ if (theTargetReturnType.isAssignableFrom(pd.getPropertyType())) {
+ return pd.getWriteMethod();
+ }else {
+ throw new NoSuchFieldException(theClassToIntrospect + " has an mutator for field " + thePropertyName + " but it does not return type " + theTargetReturnType);
+ }
+ }
+ }
+ throw new NoSuchFieldException(theClassToIntrospect + " has no mutator for field " + thePropertyName);
+ }
+}
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/reflection/JavaReflectBeanUtil.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/reflection/JavaReflectBeanUtil.java
new file mode 100644
index 00000000000..a8c8bd98dd3
--- /dev/null
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/reflection/JavaReflectBeanUtil.java
@@ -0,0 +1,63 @@
+package ca.uhn.fhir.util.reflection;
+
+import java.lang.reflect.Method;
+
+import org.apache.commons.lang3.text.WordUtils;
+
+import ca.uhn.fhir.context.ConfigurationException;
+
+/*
+ * #%L
+ * HAPI FHIR - Core Library
+ * %%
+ * Copyright (C) 2014 - 2015 University Health Network
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * #L%
+ */
+
+public class JavaReflectBeanUtil implements IBeanUtils {
+
+ @Override
+ public Method findAccessor(Class> theClassToIntrospect, Class> theTargetReturnType, String thePropertyName)
+ throws NoSuchFieldException {
+ String methodName = "get" + WordUtils.capitalize(thePropertyName);
+ try {
+ Method method = theClassToIntrospect.getMethod(methodName);
+ if (theTargetReturnType.isAssignableFrom(method.getReturnType())) {
+ return method;
+ }
+ } catch (NoSuchMethodException e) {
+ // fall through
+ } catch (SecurityException e) {
+ throw new ConfigurationException("Failed to scan class '" + theClassToIntrospect + "' because of a security exception", e);
+ }
+ throw new NoSuchFieldException(theClassToIntrospect + " has no accessor for field " + thePropertyName);
+ }
+
+ @Override
+ public Method findMutator(Class> theClassToIntrospect, Class> theTargetArgumentType, String thePropertyName)
+ throws NoSuchFieldException {
+ String methodName = "set" + WordUtils.capitalize(thePropertyName);
+ try {
+ return theClassToIntrospect.getMethod(methodName, theTargetArgumentType);
+ } catch (NoSuchMethodException e) {
+ //fall through
+ } catch (SecurityException e) {
+ throw new ConfigurationException("Failed to scan class '" + theClassToIntrospect + "' because of a security exception", e);
+ }
+ throw new NoSuchFieldException(theClassToIntrospect + " has an mutator for field " + thePropertyName + " but it does not return type " + theTargetArgumentType);
+
+ }
+
+}
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/validation/BaseValidationContext.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/validation/BaseValidationContext.java
index cb0e7aabaae..9cf24acd05c 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/validation/BaseValidationContext.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/validation/BaseValidationContext.java
@@ -23,9 +23,8 @@ package ca.uhn.fhir.validation;
import java.util.ArrayList;
import java.util.List;
-import org.thymeleaf.util.Validate;
-
import ca.uhn.fhir.context.FhirContext;
+import ca.uhn.fhir.util.ObjectUtil;
abstract class BaseValidationContext implements IValidationContext {
@@ -38,7 +37,7 @@ abstract class BaseValidationContext implements IValidationContext {
@Override
public void addValidationMessage(SingleValidationMessage theMessage) {
- Validate.notNull(theMessage, "theMessage must not be null");
+ ObjectUtil.requireNonNull(theMessage, "theMessage must not be null");
myMessages.add(theMessage);
}
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/validation/FhirValidator.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/validation/FhirValidator.java
index 1d03cf0d89a..a91e40e51db 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/validation/FhirValidator.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/validation/FhirValidator.java
@@ -32,6 +32,7 @@ import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.Bundle;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.util.OperationOutcomeUtil;
+import ca.uhn.fhir.validation.schematron.SchematronProvider;
/**
* Resource validator, which checks resources for compliance against various validation schemes (schemas, schematrons, profiles, etc.)
@@ -49,9 +50,6 @@ public class FhirValidator {
private static final String I18N_KEY_NO_PHLOC_ERROR = FhirValidator.class.getName() + ".noPhlocError";
- private static final String I18N_KEY_NO_PHLOC_WARNING = FhirValidator.class.getName() + ".noPhlocWarningOnStartup";
- private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirValidator.class);
-
private static volatile Boolean ourPhlocPresentOnClasspath;
private final FhirContext myContext;
private List myValidators = new ArrayList();
@@ -63,13 +61,7 @@ public class FhirValidator {
myContext = theFhirContext;
if (ourPhlocPresentOnClasspath == null) {
- try {
- Class.forName("com.phloc.schematron.ISchematronResource");
- ourPhlocPresentOnClasspath = true;
- } catch (ClassNotFoundException e) {
- ourLog.info(theFhirContext.getLocalizer().getMessage(I18N_KEY_NO_PHLOC_WARNING));
- ourPhlocPresentOnClasspath = false;
- }
+ ourPhlocPresentOnClasspath = SchematronProvider.isScematronAvailable(theFhirContext);
}
}
@@ -110,7 +102,12 @@ public class FhirValidator {
* Should the validator validate the resource against the base schema (the schema provided with the FHIR distribution itself)
*/
public synchronized boolean isValidateAgainstStandardSchematron() {
- return haveValidatorOfType(SchematronBaseValidator.class);
+ if (!ourPhlocPresentOnClasspath) {
+ return false; // No need to ask since we dont have Phloc. Also Class.forname will complain
+ // about missing phloc import.
+ }
+ Class extends IValidatorModule> cls = SchematronProvider.getSchematronValidatorClass();
+ return haveValidatorOfType(cls);
}
/**
@@ -147,7 +144,9 @@ public class FhirValidator {
if (theValidateAgainstStandardSchematron && !ourPhlocPresentOnClasspath) {
throw new IllegalArgumentException(myContext.getLocalizer().getMessage(I18N_KEY_NO_PHLOC_ERROR));
}
- addOrRemoveValidator(theValidateAgainstStandardSchematron, SchematronBaseValidator.class, new SchematronBaseValidator(myContext));
+ Class extends IValidatorModule> cls = SchematronProvider.getSchematronValidatorClass();
+ IValidatorModule instance = SchematronProvider.getSchematronValidatorInstance(myContext);
+ addOrRemoveValidator(theValidateAgainstStandardSchematron, cls, instance);
return this;
}
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/validation/SchemaBaseValidator.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/validation/SchemaBaseValidator.java
index 57d6fa7f34c..cebd80a4693 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/validation/SchemaBaseValidator.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/validation/SchemaBaseValidator.java
@@ -53,7 +53,9 @@ import ca.uhn.fhir.model.api.Bundle;
import ca.uhn.fhir.rest.server.EncodingEnum;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
-class SchemaBaseValidator implements IValidatorModule {
+public class SchemaBaseValidator implements IValidatorModule {
+ public static final String RESOURCES_JAR_NOTE = "Note that as of HAPI FHIR 1.2, DSTU2 validation files are kept in a separate JAR (hapi-fhir-validation-resources-XXX.jar) which must be added to your classpath. See the HAPI FHIR download page for more information.";
+
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(SchemaBaseValidator.class);
private static final Set SCHEMA_NAMES;
@@ -129,7 +131,7 @@ class SchemaBaseValidator implements IValidatorModule {
ourLog.debug("Going to load resource: {}", pathToBase);
InputStream baseIs = FhirValidator.class.getResourceAsStream(pathToBase);
if (baseIs == null) {
- throw new InternalErrorException("Schema not found. " + SchematronBaseValidator.RESOURCES_JAR_NOTE);
+ throw new InternalErrorException("Schema not found. " + RESOURCES_JAR_NOTE);
}
baseIs = new BOMInputStream(baseIs, false);
InputStreamReader baseReader = new InputStreamReader(baseIs, Charset.forName("UTF-8"));
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/validation/ValidationContext.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/validation/ValidationContext.java
index a7cdb87a951..843f676b553 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/validation/ValidationContext.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/validation/ValidationContext.java
@@ -21,7 +21,6 @@ package ca.uhn.fhir.validation;
*/
import org.hl7.fhir.instance.model.api.IBaseResource;
-import org.thymeleaf.util.Validate;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.Bundle;
@@ -29,8 +28,9 @@ import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.rest.method.MethodUtil;
import ca.uhn.fhir.rest.server.EncodingEnum;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
+import ca.uhn.fhir.util.ObjectUtil;
-class ValidationContext extends BaseValidationContext implements IValidationContext {
+public class ValidationContext extends BaseValidationContext implements IValidationContext {
private final IEncoder myEncoder;
private final T myResource;
@@ -136,8 +136,8 @@ class ValidationContext extends BaseValidationContext implements IValidati
}
public static IValidationContext forText(final FhirContext theContext, final String theResourceBody) {
- Validate.notNull(theContext, "theContext can not be null");
- Validate.notEmpty(theResourceBody, "theResourceBody can not be null or empty");
+ ObjectUtil.requireNonNull(theContext, "theContext can not be null");
+ ObjectUtil.requireNotEmpty(theResourceBody, "theResourceBody can not be null or empty");
return new BaseValidationContext(theContext) {
private EncodingEnum myEncoding;
@@ -169,5 +169,4 @@ class ValidationContext extends BaseValidationContext implements IValidati
};
}
-
}
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/validation/SchematronBaseValidator.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/validation/schematron/SchematronBaseValidator.java
similarity index 88%
rename from hapi-fhir-base/src/main/java/ca/uhn/fhir/validation/SchematronBaseValidator.java
rename to hapi-fhir-base/src/main/java/ca/uhn/fhir/validation/schematron/SchematronBaseValidator.java
index 2b100b0ab40..98397a8f1a7 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/validation/SchematronBaseValidator.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/validation/schematron/SchematronBaseValidator.java
@@ -1,4 +1,4 @@
-package ca.uhn.fhir.validation;
+package ca.uhn.fhir.validation.schematron;
/*
* #%L
@@ -37,6 +37,13 @@ import ca.uhn.fhir.model.api.Bundle;
import ca.uhn.fhir.model.api.BundleEntry;
import ca.uhn.fhir.rest.server.EncodingEnum;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
+import ca.uhn.fhir.validation.FhirValidator;
+import ca.uhn.fhir.validation.IValidationContext;
+import ca.uhn.fhir.validation.IValidatorModule;
+import ca.uhn.fhir.validation.ResultSeverityEnum;
+import ca.uhn.fhir.validation.SchemaBaseValidator;
+import ca.uhn.fhir.validation.SingleValidationMessage;
+import ca.uhn.fhir.validation.ValidationContext;
import com.phloc.commons.error.IResourceError;
import com.phloc.commons.error.IResourceErrorGroup;
@@ -44,13 +51,16 @@ import com.phloc.schematron.ISchematronResource;
import com.phloc.schematron.SchematronHelper;
import com.phloc.schematron.xslt.SchematronResourceSCH;
+/**
+ * This class is only used using reflection from {@link SchematronProvider} in order
+ * to be truly optional.
+ */
public class SchematronBaseValidator implements IValidatorModule {
- static final String RESOURCES_JAR_NOTE = "Note that as of HAPI FHIR 1.2, DSTU2 validation files are kept in a separate JAR (hapi-fhir-validation-resources-XXX.jar) which must be added to your classpath. See the HAPI FHIR download page for more information.";
private Map, ISchematronResource> myClassToSchematron = new HashMap, ISchematronResource>();
private FhirContext myCtx;
- SchematronBaseValidator(FhirContext theContext) {
+ public SchematronBaseValidator(FhirContext theContext) {
myCtx = theContext;
}
@@ -126,7 +136,7 @@ public class SchematronBaseValidator implements IValidatorModule {
InputStream baseIs = FhirValidator.class.getResourceAsStream(pathToBase);
try {
if (baseIs == null) {
- throw new InternalErrorException("Failed to load schematron for resource '" + theCtx.getFhirContext().getResourceDefinition(theCtx.getResource()).getBaseDefinition().getName() + "'. " + RESOURCES_JAR_NOTE);
+ throw new InternalErrorException("Failed to load schematron for resource '" + theCtx.getFhirContext().getResourceDefinition(theCtx.getResource()).getBaseDefinition().getName() + "'. " + SchemaBaseValidator.RESOURCES_JAR_NOTE);
}
} finally {
IOUtils.closeQuietly(baseIs);
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/validation/schematron/SchematronProvider.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/validation/schematron/SchematronProvider.java
new file mode 100644
index 00000000000..a48abde04b1
--- /dev/null
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/validation/schematron/SchematronProvider.java
@@ -0,0 +1,42 @@
+package ca.uhn.fhir.validation.schematron;
+
+import java.lang.reflect.Constructor;
+
+import ca.uhn.fhir.context.FhirContext;
+import ca.uhn.fhir.validation.FhirValidator;
+import ca.uhn.fhir.validation.IValidatorModule;
+
+public class SchematronProvider {
+
+
+ private static final String I18N_KEY_NO_PHLOC_WARNING = FhirValidator.class.getName() + ".noPhlocWarningOnStartup";
+ private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirValidator.class);
+
+ public static boolean isScematronAvailable(FhirContext theFhirContext) {
+ try {
+ Class.forName("com.phloc.schematron.ISchematronResource");
+ return true;
+ } catch (ClassNotFoundException e) {
+ ourLog.info(theFhirContext.getLocalizer().getMessage(I18N_KEY_NO_PHLOC_WARNING));
+ return false;
+ }
+ }
+
+ public static Class extends IValidatorModule> getSchematronValidatorClass() {
+ try {
+ return (Class extends IValidatorModule>) Class.forName("ca.uhn.fhir.validation.schematron.SchematronBaseValidator");
+ } catch (ClassNotFoundException e) {
+ throw new IllegalStateException("Cannot resolve schematron validator ", e);
+ }
+ }
+
+ public static IValidatorModule getSchematronValidatorInstance(FhirContext myContext) {
+ try {
+ Class extends IValidatorModule> cls = getSchematronValidatorClass();
+ Constructor extends IValidatorModule> constructor = cls.getConstructor(FhirContext.class);
+ return constructor.newInstance(myContext);
+ } catch (ReflectiveOperationException e) {
+ throw new IllegalStateException("Cannot construct schematron validator ", e);
+ }
+ }
+}
diff --git a/hapi-fhir-base/src/test/java/ca/uhn/fhir/util/BeanUtilTest.java b/hapi-fhir-base/src/test/java/ca/uhn/fhir/util/BeanUtilTest.java
new file mode 100644
index 00000000000..bf195717f58
--- /dev/null
+++ b/hapi-fhir-base/src/test/java/ca/uhn/fhir/util/BeanUtilTest.java
@@ -0,0 +1,78 @@
+package ca.uhn.fhir.util;
+
+import static org.junit.Assert.*;
+
+import java.lang.reflect.Method;
+
+import org.junit.Test;
+
+import ca.uhn.fhir.util.reflection.IBeanUtils;
+import ca.uhn.fhir.util.reflection.JavaBeansBeanUtil;
+import ca.uhn.fhir.util.reflection.JavaReflectBeanUtil;
+
+public class BeanUtilTest {
+
+ @Test
+ public void testFindAccessor() throws Exception {
+ JavaBeansBeanUtil javaBeansBeanUtil = new JavaBeansBeanUtil();
+ testBeanUtilsAccessor(javaBeansBeanUtil);
+ JavaReflectBeanUtil javaReflectBeanUtil = new JavaReflectBeanUtil();
+ testBeanUtilsAccessor(javaReflectBeanUtil);
+ assertNotNull(BeanUtils.findAccessor(BeanUtilTestClass.class, String.class, "field"));
+ Method jbMGet = javaBeansBeanUtil.findAccessor(BeanUtilTestClass.class, String.class, "field");
+ Method jrMGet = javaReflectBeanUtil.findAccessor(BeanUtilTestClass.class, String.class, "field");
+ assertNotNull(jbMGet);
+ assertNotNull(jrMGet);
+ assertEquals(jbMGet, jrMGet);
+ }
+
+ @Test
+ public void testFindMutator() throws Exception {
+ JavaBeansBeanUtil javaBeansBeanUtil = new JavaBeansBeanUtil();
+ testBeanUtilsMutator(javaBeansBeanUtil);
+ JavaReflectBeanUtil javaReflectBeanUtil = new JavaReflectBeanUtil();
+ testBeanUtilsMutator(javaReflectBeanUtil);
+ assertNotNull(BeanUtils.findMutator(BeanUtilTestClass.class, String.class, "field"));
+ Method jbMSet = javaBeansBeanUtil.findMutator(BeanUtilTestClass.class, String.class, "field");
+ Method jrMSet = javaReflectBeanUtil.findMutator(BeanUtilTestClass.class, String.class, "field");
+ assertNotNull(jbMSet);
+ assertNotNull(jrMSet);
+ assertEquals(jbMSet, jrMSet);
+ }
+
+ private void testBeanUtilsAccessor(IBeanUtils util) throws Exception {
+ assertNotNull(util.findAccessor(BeanUtilTestClass.class, String.class, "field"));
+ try {
+ assertNull(util.findAccessor(BeanUtilTestClass.class, String.class, "fieldX"));
+ fail("Field is not in class");
+ } catch (NoSuchFieldException e) { }
+ try {
+ assertNull(util.findAccessor(BeanUtilTestClass.class, Integer.class, "field"));
+ fail("Field is in class, but we expect Integer as return type");
+ } catch (NoSuchFieldException e) { }
+ }
+
+ private void testBeanUtilsMutator(IBeanUtils util) throws Exception {
+ assertNotNull(util.findMutator(BeanUtilTestClass.class, String.class, "field"));
+ try {
+ assertNull(util.findMutator(BeanUtilTestClass.class, String.class, "fieldX"));
+ fail("Field is not in class");
+ } catch (NoSuchFieldException e) { }
+ try {
+ assertNull(util.findMutator(BeanUtilTestClass.class, Integer.class, "field"));
+ fail("Field is in class, but we expect Integer as parameter type");
+ } catch (NoSuchFieldException e) { }
+ }
+
+ public static class BeanUtilTestClass {
+ private String myField;
+
+ public String getField() {
+ return myField;
+ }
+
+ public void setField(String value) {
+ this.myField = value;
+ }
+ }
+}
diff --git a/hapi-fhir-base/src/test/java/ca/uhn/fhir/util/DependencyLogUtilTest.java b/hapi-fhir-base/src/test/java/ca/uhn/fhir/util/DependencyLogUtilTest.java
new file mode 100644
index 00000000000..36bf76d64ca
--- /dev/null
+++ b/hapi-fhir-base/src/test/java/ca/uhn/fhir/util/DependencyLogUtilTest.java
@@ -0,0 +1,18 @@
+package ca.uhn.fhir.util;
+
+import static org.junit.Assert.*;
+
+import org.junit.Test;
+
+import ca.uhn.fhir.util.jar.DependencyLogFactory;
+import ca.uhn.fhir.util.jar.IDependencyLog;
+
+public class DependencyLogUtilTest {
+
+ @Test
+ public void testDependencyLogFactory() {
+ IDependencyLog logger = DependencyLogFactory.createJarLogger();
+ assertNotNull(logger);
+ logger.logStaxImplementation(DependencyLogUtilTest.class);
+ }
+}
diff --git a/hapi-fhir-base/src/test/java/ca/uhn/fhir/util/ObjectUtilTest.java b/hapi-fhir-base/src/test/java/ca/uhn/fhir/util/ObjectUtilTest.java
new file mode 100644
index 00000000000..80a8d43db49
--- /dev/null
+++ b/hapi-fhir-base/src/test/java/ca/uhn/fhir/util/ObjectUtilTest.java
@@ -0,0 +1,57 @@
+package ca.uhn.fhir.util;
+
+import static org.junit.Assert.*;
+
+import org.junit.Test;
+
+public class ObjectUtilTest {
+
+ @Test
+ public void testEquals() {
+ String a = new String("a");
+ String b = new String("b");
+ assertFalse(ObjectUtil.equals(b, a));
+ assertFalse(ObjectUtil.equals(a, b));
+ assertFalse(ObjectUtil.equals(a, null));
+ assertFalse(ObjectUtil.equals(null, a));
+ assertTrue(ObjectUtil.equals(null, null));
+ assertTrue(ObjectUtil.equals(a, a));
+ }
+
+ @Test
+ public void testRequireNonNull() {
+ String message = "Must not be null in test";
+ try {
+ ObjectUtil.requireNonNull(null, message);
+ fail("should not get here.");
+ } catch (NullPointerException e) {
+ assertEquals(message, e.getMessage());
+ }
+ assertNotNull(ObjectUtil.requireNonNull("some string", message));
+ }
+
+ @Test
+ public void testRequireNotEmpty() {
+ //All these are empty, null or whitespace strings.
+ testRequireNotEmptyErrorScenario(null);
+ testRequireNotEmptyErrorScenario("");
+ testRequireNotEmptyErrorScenario(" ");
+ testRequireNotEmptyErrorScenario(" ");
+ //All these are non empty, some non whitespace char in the string.
+ ObjectUtil.requireNotEmpty("abc ", "");
+ ObjectUtil.requireNotEmpty(" abc ", "");
+ ObjectUtil.requireNotEmpty(" abc", "");
+
+ }
+
+ private void testRequireNotEmptyErrorScenario(String string) {
+ String message = "must not be empty in test";
+ try {
+ ObjectUtil.requireNotEmpty(string, message);
+ fail("should not get here.");
+ } catch (IllegalArgumentException e) {
+ assertEquals(message, e.getMessage());
+ }
+ }
+
+}
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/Dstu1BundleFactory.java b/hapi-fhir-structures-dstu/src/main/java/ca/uhn/fhir/rest/server/Dstu1BundleFactory.java
similarity index 100%
rename from hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/Dstu1BundleFactory.java
rename to hapi-fhir-structures-dstu/src/main/java/ca/uhn/fhir/rest/server/Dstu1BundleFactory.java