Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix NoClassDefFoundError for optional dependency #23

Merged
merged 4 commits into from
Oct 20, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.function.Supplier;

/**
* A factory that creates {@link JsonProvider} instances for specified JSON object types.
Expand All @@ -33,16 +32,16 @@ public final class JsonProviderFactory
private static final JsonProviderFactory INSTANCE = new JsonProviderFactory();

// Associates each class name with the assignable JsonProvider
private static final Map<String, Supplier<JsonProvider<?>>> PROVIDERS = new HashMap<>();
private static final Map<String, Class<? extends JsonProvider<?>>> PROVIDERS = new HashMap<>();

static
{
PROVIDERS.put("net.minidev.json.JSONObject", JsonSmartJsonProvider::new);
PROVIDERS.put("com.google.gson.JsonObject", GsonJsonProvider::new);
PROVIDERS.put("com.fasterxml.jackson.databind.JsonNode", JacksonJsonNodeJsonProvider::new);
PROVIDERS.put("com.fasterxml.jackson.databind.node.ObjectNode", JacksonJsonNodeJsonProvider::new);
PROVIDERS.put("org.json.JSONObject", JsonOrgJsonProvider::new);
PROVIDERS.put("io.vertx.core.json.JsonObject", VertxJsonProvider::new);
PROVIDERS.put("net.minidev.json.JSONObject", JsonSmartJsonProvider.class);
PROVIDERS.put("com.google.gson.JsonObject", GsonJsonProvider.class);
PROVIDERS.put("com.fasterxml.jackson.databind.JsonNode", JacksonJsonNodeJsonProvider.class);
PROVIDERS.put("com.fasterxml.jackson.databind.node.ObjectNode", JacksonJsonNodeJsonProvider.class);
PROVIDERS.put("org.json.JSONObject", JsonOrgJsonProvider.class);
PROVIDERS.put("io.vertx.core.json.JsonObject", VertxJsonProvider.class);
}

/**
Expand Down Expand Up @@ -72,18 +71,33 @@ private JsonProviderFactory()
* @throws NullPointerException if the specified {@code jsonObjectType} is null
* @throws IllegalArgumentException if no {@link JsonProvider} found for the specified
* {@code jsonObjectType}
* @throws IllegalStateException if unable to instantiate the target
* {@link JsonProvider}
*/
@SuppressWarnings("unchecked")
public <T> JsonProvider<T> getByType(final Class<T> jsonObjectType)
{
Objects.requireNonNull(jsonObjectType, "The search type must not be null");
return getByType(PROVIDERS, jsonObjectType);
}

@SuppressWarnings("unchecked")
<T> JsonProvider<T> getByType(final Map<String, Class<? extends JsonProvider<?>>> map,
final Class<T> jsonObjectType)
{
Objects.requireNonNull(jsonObjectType, "The type must not be null");
String className = jsonObjectType.getCanonicalName();
Supplier<JsonProvider<?>> supplier = PROVIDERS.get(className);
if (supplier == null)
Class<? extends JsonProvider<?>> providerClass = map.get(className);
if (providerClass == null)
{
throw new IllegalArgumentException("No JsonProvider available for " + className);
}
return (JsonProvider<T>) supplier.get();
try
{
return (JsonProvider<T>) providerClass.getDeclaredConstructor().newInstance();
}
catch (ReflectiveOperationException exception)
{
throw new IllegalStateException(exception);
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
/*
* Copyright 2022 obvj.net
*
* 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.
*/

package net.obvj.jsonmerge.provider;

import java.io.InputStream;
import java.util.Map.Entry;
import java.util.Set;
import java.util.function.Consumer;
import java.util.stream.Stream;

/**
* A bad {@link JsonProvider} just for testing purposes.
*
* @author oswaldo.bapvic.jr
*/
public class BadJsonProvider implements JsonProvider<Object>
{
public BadJsonProvider()
{
throw new UnsupportedOperationException("Should not be able to instantiate me");
}

@Override
public Object parse(String string)
{
return null;
}

@Override
public Object parse(InputStream inputStream)
{
return null;
}

@Override
public boolean isJsonObject(Object object)
{
return false;
}

@Override
public boolean isJsonArray(Object object)
{
return false;
}

@Override
public boolean isEmpty(Object jsonObject)
{
return false;
}

@Override
public Object newJsonObject()
{
return null;
}

@Override
public Object newJsonObject(Object sourceJsonObject)
{
return null;
}

@Override
public Object newJsonArray()
{
return null;
}

@Override
public Object newJsonArray(Object sourceJsonArray)
{
return null;
}

@Override
public Set<Entry<String, Object>> entrySet(Object jsonObject)
{
return null;
}

@Override
public Object get(Object jsonObject, String key)
{
return null;
}

@Override
public Object get(Object jsonArray, int index)
{
return null;
}

@Override
public void put(Object jsonObject, String key, Object value)
{
// Empty on purpose
}

@Override
public void putIfAbsent(Object jsonObject, String key, Object value)
{
// Empty on purpose
}

@Override
public void add(Object jsonArray, Object element)
{
// Empty on purpose
}

@Override
public void set(Object jsonArray, int index, Object element)
{
// Empty on purpose
}

@Override
public int indexOf(Object jsonArray, Object element)
{
return 0;
}

@Override
public void forEachElementInArray(Object jsonArray, Consumer<? super Object> action)
{
// Empty on purpose
}

@Override
public boolean arrayContains(Object jsonArray, Object element)
{
return false;
}

@Override
public Stream<Object> stream(Object jsonArray)
{
return null;
}

@Override
public int size(Object jsonArray)
{
return 0;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertSame;

import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;

import org.junit.jupiter.api.Test;

import com.fasterxml.jackson.databind.JsonNode;
Expand Down Expand Up @@ -69,7 +73,17 @@ void getByType_invalidType_illegalArgumentException()
void getByType_null_npeWithProperMessage()
{
assertThat(() -> factory.getByType(null), throwsException(NullPointerException.class)
.withMessage("The search type must not be null"));
.withMessage("The type must not be null"));
}

@Test
void getByType_illegalReflectiveOperationException_illegalArgumentException()
{
Map<String, Class<? extends JsonProvider<?>>> providers = new HashMap<>();
providers.put("java.lang.Object", BadJsonProvider.class);
assertThat(() -> factory.getByType(providers, Object.class),
throwsException(IllegalStateException.class)
.withCause(InvocationTargetException.class));
}

@Test
Expand Down