Skip to content

Instantly share code, notes, and snippets.

@anpieber
Created September 12, 2011 10:36
Show Gist options
  • Select an option

  • Save anpieber/1210983 to your computer and use it in GitHub Desktop.

Select an option

Save anpieber/1210983 to your computer and use it in GitHub Desktop.
diff --git a/core/api/src/main/java/org/openengsb/core/api/remote/CustomJsonMarshaller.java b/core/api/src/main/java/org/openengsb/core/api/remote/CustomJsonMarshaller.java
new file mode 100644
index 0000000..a598eef
--- /dev/null
+++ b/core/api/src/main/java/org/openengsb/core/api/remote/CustomJsonMarshaller.java
@@ -0,0 +1,36 @@
+/**
+ * Licensed to the Austrian Association for Software Tool Integration (AASTI)
+ * under one or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information regarding copyright
+ * ownership. The AASTI licenses this file to you 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.
+ */
+
+package org.openengsb.core.api.remote;
+
+/**
+ * Custom mapper interface used in case of json argument marshalling. The problem is that java does not have static type
+ * information which finally requires that you add custom marshaller. For example the default marshalling process has no
+ * idea about e.g. of a generic list of type X.
+ *
+ * To configure the custom marshaller for an argument use the {@link UseCustomJasonMarshaller} annotation at the param
+ * with the classname. The two conditions which have to be fullfilled are that the class has a default constructure and
+ * that it implements this interface.
+ */
+public interface CustomJsonMarshaller<OutputType> {
+
+ /**
+ * Map an object argument with (optional) use of the mapper into the specific object of type OutputType.
+ */
+ OutputType transformArg(Object arg);
+
+}
diff --git a/core/api/src/main/java/org/openengsb/core/api/remote/UseCustomJasonMarshaller.java b/core/api/src/main/java/org/openengsb/core/api/remote/UseCustomJasonMarshaller.java
new file mode 100644
index 0000000..9b7e7e1
--- /dev/null
+++ b/core/api/src/main/java/org/openengsb/core/api/remote/UseCustomJasonMarshaller.java
@@ -0,0 +1,39 @@
+/**
+ * Licensed to the Austrian Association for Software Tool Integration (AASTI)
+ * under one or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information regarding copyright
+ * ownership. The AASTI licenses this file to you 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.
+ */
+
+package org.openengsb.core.api.remote;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation defining which {@link CustomJsonMarshaller} to use for argument.
+ */
+@Documented
+@Retention(value = RetentionPolicy.RUNTIME)
+@Target(ElementType.PARAMETER)
+public @interface UseCustomJasonMarshaller {
+
+ /**
+ * Nothing more required than to define which class to use to execute the marshaling.
+ */
+ Class<? extends CustomJsonMarshaller<?>> value();
+
+}
diff --git a/core/services/src/main/java/org/openengsb/core/services/internal/RequestHandlerImpl.java b/core/services/src/main/java/org/openengsb/core/services/internal/RequestHandlerImpl.java
index cc9d9cf..4360534 100644
--- a/core/services/src/main/java/org/openengsb/core/services/internal/RequestHandlerImpl.java
+++ b/core/services/src/main/java/org/openengsb/core/services/internal/RequestHandlerImpl.java
@@ -17,6 +17,7 @@
package org.openengsb.core.services.internal;
+import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
@@ -25,12 +26,16 @@ import java.util.Map;
import org.openengsb.core.api.Constants;
import org.openengsb.core.api.context.ContextHolder;
+import org.openengsb.core.api.remote.CustomJsonMarshaller;
import org.openengsb.core.api.remote.MethodCall;
import org.openengsb.core.api.remote.MethodResult;
import org.openengsb.core.api.remote.MethodResult.ReturnType;
import org.openengsb.core.api.remote.RequestHandler;
+import org.openengsb.core.api.remote.UseCustomJasonMarshaller;
import org.openengsb.core.common.OpenEngSBCoreServices;
+import com.google.common.base.Throwables;
+
public class RequestHandlerImpl implements RequestHandler {
@Override
@@ -41,13 +46,49 @@ public class RequestHandlerImpl implements RequestHandler {
ContextHolder.get().setCurrentContextId(contextId);
}
Object service = retrieveOpenEngSBService(call);
- Object[] args = call.getArgs();
Method method = findMethod(service, call.getMethodName(), getArgTypes(call));
+ Object[] args = retrieveArguments(call, method);
MethodResult methodResult = invokeMethod(service, method, args);
methodResult.setMetaData(call.getMetaData());
return methodResult;
}
+ private Object[] retrieveArguments(MethodCall call, Method method) {
+ Annotation[][] parameterAnnotations = method.getParameterAnnotations();
+ Object[] originalArgs = call.getArgs();
+ for (int i = 0; i < originalArgs.length; i++) {
+ Annotation[] currentArgAnnotations = parameterAnnotations[i];
+ Class<? extends CustomJsonMarshaller<?>> transformationAnnotation =
+ searchForTransformationAnnotation(currentArgAnnotations);
+ if (transformationAnnotation == null) {
+ continue;
+ }
+ CustomJsonMarshaller<?> transformationInstance = createTransformationInstance(transformationAnnotation);
+ originalArgs[i] = transformationInstance.transformArg(originalArgs[i]);
+ }
+ return originalArgs;
+ }
+
+ private CustomJsonMarshaller<?> createTransformationInstance(
+ Class<? extends CustomJsonMarshaller<?>> transformationAnnotation) {
+ try {
+ return transformationAnnotation.newInstance();
+ } catch (Exception e) {
+ throw new IllegalStateException("It's not possible to create transformation because of "
+ + Throwables.getStackTraceAsString(e));
+ }
+ }
+
+ private Class<? extends CustomJsonMarshaller<?>> searchForTransformationAnnotation(
+ Annotation[] currentArgAnnotations) {
+ for (Annotation annotation : currentArgAnnotations) {
+ if (annotation instanceof UseCustomJasonMarshaller) {
+ return ((UseCustomJasonMarshaller) annotation).value();
+ }
+ }
+ return null;
+ }
+
private Object retrieveOpenEngSBService(MethodCall call) {
Map<String, String> metaData = call.getMetaData();
String serviceId = metaData.get("serviceId");
diff --git a/core/services/src/test/java/org/openengsb/core/services/internal/RequestHandlerImplTest.java b/core/services/src/test/java/org/openengsb/core/services/internal/RequestHandlerImplTest.java
index a84ee4b..eb9dd9c 100644
--- a/core/services/src/test/java/org/openengsb/core/services/internal/RequestHandlerImplTest.java
+++ b/core/services/src/test/java/org/openengsb/core/services/internal/RequestHandlerImplTest.java
@@ -33,14 +33,17 @@ import java.util.Map;
import org.junit.Before;
import org.junit.Test;
import org.openengsb.core.api.OsgiUtilsService;
+import org.openengsb.core.api.remote.CustomJsonMarshaller;
import org.openengsb.core.api.remote.MethodCall;
import org.openengsb.core.api.remote.MethodResult;
import org.openengsb.core.api.remote.RequestHandler;
+import org.openengsb.core.api.remote.UseCustomJasonMarshaller;
import org.openengsb.core.common.OpenEngSBCoreServices;
import org.openengsb.core.common.util.DefaultOsgiUtilsService;
import org.openengsb.core.test.AbstractOsgiMockServiceTest;
import org.osgi.framework.BundleContext;
+import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableMap;
public class RequestHandlerImplTest extends AbstractOsgiMockServiceTest {
@@ -52,6 +55,16 @@ public class RequestHandlerImplTest extends AbstractOsgiMockServiceTest {
Integer test(Integer arg);
}
+ public static class CustomMarshaller implements CustomJsonMarshaller<Integer> {
+
+ @Override
+ public Integer transformArg(Object arg) {
+ Preconditions.checkArgument(arg instanceof Integer);
+ return (Integer) arg + 1;
+ }
+
+ }
+
@Before
public void setup() throws Exception {
requestHandler = new RequestHandlerImpl();
@@ -64,6 +77,12 @@ public class RequestHandlerImplTest extends AbstractOsgiMockServiceTest {
return mockService;
}
+ private TestInterface registerServiceWithProps(TestInterface mockService, Map<String, Object> propData) {
+ Dictionary<String, Object> props = new Hashtable<String, Object>(propData);
+ registerService(mockService, props, TestInterface.class);
+ return mockService;
+ }
+
@Test
public void testCallByServiceId_shouldCallService() throws Exception {
TestInterface mockService = mockService(TestInterface.class, "testid");
@@ -110,6 +129,26 @@ public class RequestHandlerImplTest extends AbstractOsgiMockServiceTest {
}
@Test
+ public void testCallByFilterAndServiceIdWithCustomMarshaller_shouldCallService() throws Exception {
+ Map<String, Object> propData =
+ ImmutableMap.of("testprop", (Object) new String[]{ "blub", "bleh", }, "id", "xxx");
+ TestInterface realObject = new TestInterface() {
+ @Override
+ public Integer test(@UseCustomJasonMarshaller(CustomMarshaller.class) Integer arg) {
+ return arg;
+ }
+ };
+ registerServiceWithProps(realObject, propData);
+
+ Map<String, String> metaData = ImmutableMap.of("serviceFilter", "(testprop=blub)", "serviceId", "xxx");
+ MethodCall c = new MethodCall("test", new Object[]{ 42 }, metaData);
+ MethodResult result = requestHandler.handleCall(c);
+
+ assertThat(result.getClassName(), is(Integer.class.getName()));
+ assertThat((Integer) result.getArg(), is(43));
+ }
+
+ @Test
public void testCallButBothAttrsNull_shouldThrowException() throws Exception {
Map<String, Object> propData =
ImmutableMap.of("testprop", (Object) new String[]{ "bla", "bleh", });
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment