Skip to content

Commit 6725897

Browse files
committed
potential support for customize gson
1 parent 385d93a commit 6725897

File tree

6 files changed

+76
-19
lines changed

6 files changed

+76
-19
lines changed

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
<maven.compiler.source>1.8</maven.compiler.source>
2222
<maven.compiler.target>1.8</maven.compiler.target>
2323
<azure.functions.java.core.library.version>1.2.0</azure.functions.java.core.library.version>
24-
<azure.functions.java.spi>1.0.0</azure.functions.java.spi>
24+
<azure.functions.java.spi>1.1.0</azure.functions.java.spi>
2525
<azure.functions.java.library.version>2.2.0</azure.functions.java.library.version>
2626
<jupiter.version>5.9.1</jupiter.version>
2727
<mockito-core.version>4.11.0</mockito-core.version>

src/main/java/com/microsoft/azure/functions/worker/Util.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
package com.microsoft.azure.functions.worker;
22

3+
import com.google.gson.Gson;
4+
import com.microsoft.azure.functions.spi.inject.GsonInstanceInjector;
5+
36
public class Util {
7+
private static Gson gsonInstance;
8+
private static final Object utilLock = new Object();
49
public static boolean isTrue(String value) {
510
if(value != null && (value.equalsIgnoreCase("true") || value.equalsIgnoreCase("1"))) {
611
return true;
@@ -11,4 +16,19 @@ public static boolean isTrue(String value) {
1116
public static String getJavaVersion() {
1217
return String.join(" - ", System.getProperty("java.home"), System.getProperty("java.version"));
1318
}
19+
20+
public static void setGsonInstance(Gson instance) {
21+
if (gsonInstance == null) {
22+
synchronized (utilLock) {
23+
if (gsonInstance == null) {
24+
gsonInstance = instance;
25+
}
26+
}
27+
}
28+
}
29+
30+
public static Gson getGsonInstance() {
31+
return gsonInstance;
32+
}
33+
1434
}

src/main/java/com/microsoft/azure/functions/worker/binding/RpcJsonDataSource.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import java.util.Collection;
66
import java.util.List;
77

8+
import com.microsoft.azure.functions.worker.Util;
89
import org.apache.commons.lang3.reflect.TypeUtils;
910

1011
import com.google.gson.Gson;
@@ -17,7 +18,7 @@ public RpcJsonDataSource(String name, String value) {
1718
super(name, value, JSON_DATA_OPERATIONS);
1819
}
1920

20-
public static final Gson gson = new Gson();
21+
public static final Gson gson = Util.getGsonInstance();
2122
public static final JsonParser gsonParser = new JsonParser();
2223
private static final DataOperations<String, Object> JSON_DATA_OPERATIONS = new DataOperations<>();
2324

src/main/java/com/microsoft/azure/functions/worker/broker/JavaFunctionBroker.java

Lines changed: 37 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,13 @@
77
import java.util.*;
88
import java.util.concurrent.ConcurrentHashMap;
99

10+
import com.google.gson.Gson;
1011
import com.microsoft.azure.functions.internal.spi.middleware.Middleware;
1112
import com.microsoft.azure.functions.rpc.messages.*;
1213
import com.microsoft.azure.functions.spi.inject.FunctionInstanceInjector;
14+
import com.microsoft.azure.functions.spi.inject.GsonInstanceInjector;
1315
import com.microsoft.azure.functions.worker.Constants;
16+
import com.microsoft.azure.functions.worker.Util;
1417
import com.microsoft.azure.functions.worker.WorkerLogManager;
1518
import com.microsoft.azure.functions.worker.binding.BindingDataStore;
1619
import com.microsoft.azure.functions.worker.binding.ExecutionContextDataSource;
@@ -38,7 +41,7 @@ public class JavaFunctionBroker {
3841
private volatile FunctionInstanceInjector functionInstanceInjector;
3942
private final Object oneTimeLogicInitializationLock = new Object();
4043

41-
private FunctionInstanceInjector newInstanceInjector() {
44+
private FunctionInstanceInjector newFunctionInstanceInjector() {
4245
return new FunctionInstanceInjector() {
4346
@Override
4447
public <T> T getInstance(Class<T> functionClass) throws Exception {
@@ -53,20 +56,20 @@ public JavaFunctionBroker(ClassLoaderProvider classLoaderProvider) {
5356
}
5457

5558
public void loadMethod(FunctionMethodDescriptor descriptor, Map<String, BindingInfo> bindings)
56-
throws ClassNotFoundException, NoSuchMethodException, IOException {
59+
throws Exception {
5760
descriptor.validate();
5861
addSearchPathsToClassLoader(descriptor);
5962
initializeOneTimeLogics();
6063
FunctionDefinition functionDefinition = new FunctionDefinition(descriptor, bindings, classLoaderProvider);
6164
this.methods.put(descriptor.getId(), new ImmutablePair<>(descriptor.getName(), functionDefinition));
6265
}
6366

64-
private void initializeOneTimeLogics() {
67+
private void initializeOneTimeLogics() throws Exception{
6568
if (!oneTimeLogicInitialized) {
6669
synchronized (oneTimeLogicInitializationLock) {
6770
if (!oneTimeLogicInitialized) {
6871
initializeInvocationChainFactory();
69-
initializeFunctionInstanceInjector();
72+
initializeInstanceInjector();
7073
oneTimeLogicInitialized = true;
7174
}
7275
}
@@ -90,28 +93,45 @@ private void initializeInvocationChainFactory() {
9093
this.invocationChainFactory = new InvocationChainFactory(middlewares);
9194
}
9295

93-
private void initializeFunctionInstanceInjector() {
96+
private void initializeInstanceInjector() throws Exception{
9497
ClassLoader prevContextClassLoader = Thread.currentThread().getContextClassLoader();
9598
try {
9699
//ServiceLoader will use thread context classloader to verify loaded class
97100
Thread.currentThread().setContextClassLoader(classLoaderProvider.createClassLoader());
98-
Iterator<FunctionInstanceInjector> iterator = ServiceLoader.load(FunctionInstanceInjector.class).iterator();
99-
if (iterator.hasNext()) {
100-
this.functionInstanceInjector = iterator.next();
101-
WorkerLogManager.getSystemLogger().info("Load function instance injector: " + this.functionInstanceInjector.getClass().getName());
102-
if (iterator.hasNext()){
103-
WorkerLogManager.getSystemLogger().warning("Customer function app has multiple FunctionInstanceInjector implementations.");
104-
throw new RuntimeException("Customer function app has multiple FunctionInstanceInjector implementations");
105-
}
106-
}else {
107-
this.functionInstanceInjector = newInstanceInjector();
108-
WorkerLogManager.getSystemLogger().info("Didn't find any function instance injector, creating function class instance every invocation.");
109-
}
101+
loadFunctionInstanceInjector();
102+
loadGsonInstanceInjector();
110103
} finally {
111104
Thread.currentThread().setContextClassLoader(prevContextClassLoader);
112105
}
113106
}
114107

108+
private void loadFunctionInstanceInjector() {
109+
Iterator<FunctionInstanceInjector> iterator = ServiceLoader.load(FunctionInstanceInjector.class).iterator();
110+
if (iterator.hasNext()) {
111+
this.functionInstanceInjector = iterator.next();
112+
WorkerLogManager.getSystemLogger().info("Load function instance injector: " + this.functionInstanceInjector.getClass().getName());
113+
if (iterator.hasNext()){
114+
WorkerLogManager.getSystemLogger().warning("Customer function app has multiple FunctionInstanceInjector implementations.");
115+
throw new RuntimeException("Customer function app has multiple FunctionInstanceInjector implementations");
116+
}
117+
}else {
118+
this.functionInstanceInjector = newFunctionInstanceInjector();
119+
WorkerLogManager.getSystemLogger().info("Didn't find any function instance injector, creating function class instance every invocation.");
120+
}
121+
}
122+
123+
private void loadGsonInstanceInjector() throws Exception{
124+
Iterator<GsonInstanceInjector> iterator = ServiceLoader.load(GsonInstanceInjector.class).iterator();
125+
if (iterator.hasNext()) {
126+
GsonInstanceInjector gsonInstanceInjector = iterator.next();
127+
Util.setGsonInstance(gsonInstanceInjector.getGsonInstance());
128+
WorkerLogManager.getSystemLogger().info("Load gson instance injector: " + gsonInstanceInjector.getClass().getName());
129+
}else {
130+
Util.setGsonInstance(new Gson());
131+
WorkerLogManager.getSystemLogger().info("Didn't find any gson instance injector, creating function class instance every invocation.");
132+
}
133+
}
134+
115135
private FunctionExecutionMiddleware getFunctionExecutionMiddleWare() {
116136
FunctionExecutionMiddleware functionExecutionMiddleware = new FunctionExecutionMiddleware(
117137
JavaMethodExecutors.createJavaMethodExecutor(this.classLoaderProvider.createClassLoader()));

src/test/java/com/microsoft/azure/functions/worker/binding/tests/RpcByteArrayDataSourceTest.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,24 @@
44
import java.lang.invoke.WrongMethodTypeException;
55
import java.util.Optional;
66

7+
import com.google.gson.Gson;
8+
import com.microsoft.azure.functions.worker.Util;
79
import org.apache.commons.lang3.ArrayUtils;
810

911
import com.google.protobuf.ByteString;
1012
import com.microsoft.azure.functions.worker.binding.BindingData;
1113
import com.microsoft.azure.functions.worker.binding.RpcByteArrayDataSource;
14+
import org.junit.jupiter.api.BeforeAll;
1215
import org.junit.jupiter.api.Test;
1316
import static org.junit.jupiter.api.Assertions.assertEquals;
1417

1518
public class RpcByteArrayDataSourceTest {
1619

20+
@BeforeAll
21+
public static void setGsonInstance() {
22+
Util.setGsonInstance(new Gson());
23+
}
24+
1725
@Test
1826
public void rpcByteArrayDataSource_To_byteArray() {
1927
String sourceKey = "testByteArray";

src/test/java/com/microsoft/azure/functions/worker/binding/tests/RpcStringDataSourceTest.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,14 @@
88
import java.util.List;
99
import java.util.Optional;
1010

11+
import com.google.gson.Gson;
1112
import com.google.gson.JsonSyntaxException;
13+
import com.microsoft.azure.functions.worker.Util;
1214
import com.microsoft.azure.functions.worker.binding.BindingData;
1315
import com.microsoft.azure.functions.worker.binding.RpcJsonDataSource;
1416
import com.microsoft.azure.functions.worker.binding.RpcStringDataSource;
1517
import org.junit.jupiter.api.Assertions;
18+
import org.junit.jupiter.api.BeforeAll;
1619
import org.junit.jupiter.api.Test;
1720

1821
import static org.junit.jupiter.api.Assertions.*;
@@ -32,6 +35,11 @@ public void FunctionWithPOJOListInput(ArrayList<TestPOJO> items) {
3235
public void FunctionWithStringListInput(List<String> items) {
3336
}
3437

38+
@BeforeAll
39+
public static void setGsonInstance() {
40+
Util.setGsonInstance(new Gson());
41+
}
42+
3543
@Test
3644
public void rpcStringDataSource_To_String() {
3745
String sourceKey = "testString";

0 commit comments

Comments
 (0)