Skip to content

Commit

Permalink
Add duplicate class check
Browse files Browse the repository at this point in the history
  • Loading branch information
swallez committed Oct 17, 2023
1 parent 3414ffd commit 1d539d6
Show file tree
Hide file tree
Showing 4 changed files with 153 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,9 @@
import co.elastic.clients.transport.endpoints.BinaryResponse;
import co.elastic.clients.transport.endpoints.BooleanResponse;
import co.elastic.clients.transport.endpoints.EndpointWithResponseMapperAttr;
import co.elastic.clients.util.DuplicateResourceFinder;
import co.elastic.clients.util.ObjectBuilder;

import java.io.IOException;
import java.lang.reflect.Type;
import java.util.function.Function;
Expand All @@ -123,6 +125,12 @@
*/
public class ElasticsearchClient extends ApiClient<ElasticsearchTransport, ElasticsearchClient> {

static {
// Make sure we don't have several versions of this class. This may happen if
// several flavors of the client (Stack and Serverless) are present in the classpath.
DuplicateResourceFinder.ensureClassUniqueness(ElasticsearchClient.class);
}

public ElasticsearchClient(ElasticsearchTransport transport) {
super(transport, null);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. 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 co.elastic.clients.util;

import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;

public class DuplicateResourceFinder {

private static volatile boolean ENABLED = true;

/**
* Disables the resource uniqueness checks. Use with caution, as it will mask problems that may hit later.
*/
public static void enableCheck(boolean enabled) {
ENABLED = enabled;
}

/**
* Ensure a class is only defined once in this class' classpath
*/
public static void ensureClassUniqueness(Class<?> clazz) {
String name = clazz.getName();
String resource = clazz.getName().replace('.', '/') + ".class";
ensureResourceUniqueness(resource, name, DuplicateResourceFinder.class.getClassLoader());
}

public static void ensureResourceUniqueness(String path) {
ensureResourceUniqueness(path, path, DuplicateResourceFinder.class.getClassLoader());
}

private static void ensureResourceUniqueness(String path, String name, ClassLoader classLoader) {
if (!ENABLED) {
return;
}

// With Java9 modules, will work only with exported classes/resources. This is actually
// what we want, as non-exported classes/resources will not conflict.
List<URL> list = new ArrayList<>();
try {
Enumeration<URL> resources = classLoader.getResources(path);
while (resources.hasMoreElements()) {
list.add(resources.nextElement());
}
} catch (IOException ioe) {
// Ignore
}

if (list.size() > 1) {
StringBuilder sb = new StringBuilder("Several versions of ")
.append(name)
.append(" were found. This can cause conflicts, please fix the classpath:\n");
for (URL url: list) {
sb.append(" ").append(url.toString()).append("\n");
}
sb.append(" See the Java API client's troubleshooting documentation for more information.\n");
throw new RuntimeException(sb.toString());
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. 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 co.elastic.clients.util;

import com.fasterxml.jackson.databind.ext.CoreXMLSerializers;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

class DuplicateResourceFinderTest extends Assertions {

@Test
public void testDuplicateCheck() {

Exception e = assertThrows(RuntimeException.class, () -> {
DuplicateResourceFinder.ensureClassUniqueness(CoreXMLSerializers.class);
});
assertTrue(e.getMessage().contains("Several versions of"));

// Disabling the test should not throw an exception
DuplicateResourceFinder.enableCheck(false);
DuplicateResourceFinder.ensureClassUniqueness(CoreXMLSerializers.class);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. 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 com.fasterxml.jackson.databind.ext;

// A "duplicate" of a class that exists in the project's dependencies.
// It's not actually used by the project, so the duplicate won't harm and is used in DuplicateResourceFinderTest
public class CoreXMLSerializers {
}

0 comments on commit 1d539d6

Please sign in to comment.