Polishing

This commit is contained in:
Juergen Hoeller 2018-11-20 22:06:44 +01:00
parent a3d763d137
commit 8c7579eba8
8 changed files with 60 additions and 65 deletions

View File

@ -217,7 +217,7 @@ public class EnableAsyncTests {
} }
@Test @Test
public void customExecutorConfig() throws InterruptedException { public void customExecutorConfig() {
// Arrange // Arrange
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.register(CustomExecutorConfig.class); ctx.register(CustomExecutorConfig.class);

View File

@ -23,28 +23,29 @@ import javax.naming.NamingException;
import org.springframework.jndi.JndiTemplate; import org.springframework.jndi.JndiTemplate;
/** /**
* Simple extension of the JndiTemplate class that always returns * Simple extension of the JndiTemplate class that always returns a given object.
* a given object. Very useful for testing. Effectively a mock object. *
* <p>Very useful for testing. Effectively a mock object.
* *
* @author Rod Johnson * @author Rod Johnson
* @author Juergen Hoeller * @author Juergen Hoeller
*/ */
public class ExpectedLookupTemplate extends JndiTemplate { public class ExpectedLookupTemplate extends JndiTemplate {
private final Map<String, Object> jndiObjects = new ConcurrentHashMap<>(); private final Map<String, Object> jndiObjects = new ConcurrentHashMap<>(16);
/** /**
* Construct a new JndiTemplate that will always return given objects * Construct a new JndiTemplate that will always return given objects for
* for given names. To be populated through {@code addObject} calls. * given names. To be populated through {@code addObject} calls.
* @see #addObject(String, Object) * @see #addObject(String, Object)
*/ */
public ExpectedLookupTemplate() { public ExpectedLookupTemplate() {
} }
/** /**
* Construct a new JndiTemplate that will always return the * Construct a new JndiTemplate that will always return the given object,
* given object, but honour only requests for the given name. * but honour only requests for the given name.
* @param name the name the client is expected to look up * @param name the name the client is expected to look up
* @param object the object that will be returned * @param object the object that will be returned
*/ */
@ -52,10 +53,8 @@ public class ExpectedLookupTemplate extends JndiTemplate {
addObject(name, object); addObject(name, object);
} }
/** /**
* Add the given object to the list of JNDI objects that this * Add the given object to the list of JNDI objects that this template will expose.
* template will expose.
* @param name the name the client is expected to look up * @param name the name the client is expected to look up
* @param object the object that will be returned * @param object the object that will be returned
*/ */
@ -63,11 +62,10 @@ public class ExpectedLookupTemplate extends JndiTemplate {
this.jndiObjects.put(name, object); this.jndiObjects.put(name, object);
} }
/** /**
* If the name is the expected name specified in the constructor, * If the name is the expected name specified in the constructor, return the
* return the object provided in the constructor. If the name is * object provided in the constructor. If the name is unexpected, a
* unexpected, a respective NamingException gets thrown. * respective NamingException gets thrown.
*/ */
@Override @Override
public Object lookup(String name) throws NamingException { public Object lookup(String name) throws NamingException {

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2016 the original author or authors. * Copyright 2002-2018 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -33,6 +33,7 @@ import javax.naming.OperationNotSupportedException;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.springframework.lang.Nullable;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
/** /**
@ -80,7 +81,9 @@ public class SimpleNamingContext implements Context {
* Create a new naming context with the given naming root, * Create a new naming context with the given naming root,
* the given name/object map, and the JNDI environment entries. * the given name/object map, and the JNDI environment entries.
*/ */
public SimpleNamingContext(String root, Hashtable<String, Object> boundObjects, Hashtable<String, Object> env) { public SimpleNamingContext(
String root, Hashtable<String, Object> boundObjects, @Nullable Hashtable<String, Object> env) {
this.root = root; this.root = root;
this.boundObjects = boundObjects; this.boundObjects = boundObjects;
if (env != null) { if (env != null) {
@ -206,6 +209,7 @@ public class SimpleNamingContext implements Context {
} }
@Override @Override
@Nullable
public Object addToEnvironment(String propName, Object propVal) { public Object addToEnvironment(String propName, Object propVal) {
return this.environment.put(propName, propVal); return this.environment.put(propName, propVal);
} }
@ -293,7 +297,7 @@ public class SimpleNamingContext implements Context {
} }
private static abstract class AbstractNamingEnumeration<T> implements NamingEnumeration<T> { private abstract static class AbstractNamingEnumeration<T> implements NamingEnumeration<T> {
private Iterator<T> iterator; private Iterator<T> iterator;
@ -353,7 +357,7 @@ public class SimpleNamingContext implements Context {
} }
private static class NameClassPairEnumeration extends AbstractNamingEnumeration<NameClassPair> { private static final class NameClassPairEnumeration extends AbstractNamingEnumeration<NameClassPair> {
private NameClassPairEnumeration(SimpleNamingContext context, String root) throws NamingException { private NameClassPairEnumeration(SimpleNamingContext context, String root) throws NamingException {
super(context, root); super(context, root);
@ -366,7 +370,7 @@ public class SimpleNamingContext implements Context {
} }
private static class BindingEnumeration extends AbstractNamingEnumeration<Binding> { private static final class BindingEnumeration extends AbstractNamingEnumeration<Binding> {
private BindingEnumeration(SimpleNamingContext context, String root) throws NamingException { private BindingEnumeration(SimpleNamingContext context, String root) throws NamingException {
super(context, root); super(context, root);

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2016 the original author or authors. * Copyright 2002-2018 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -26,7 +26,10 @@ import javax.naming.spi.NamingManager;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils; import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;
/** /**
* Simple implementation of a JNDI naming context builder. * Simple implementation of a JNDI naming context builder.
@ -42,7 +45,7 @@ import org.springframework.util.ClassUtils;
* <ul> * <ul>
* <li>{@code SingleConnectionDataSource} (using the same Connection for all getConnection calls) * <li>{@code SingleConnectionDataSource} (using the same Connection for all getConnection calls)
* <li>{@code DriverManagerDataSource} (creating a new Connection on each getConnection call) * <li>{@code DriverManagerDataSource} (creating a new Connection on each getConnection call)
* <li>Apache's Jakarta Commons DBCP offers {@code org.apache.commons.dbcp.BasicDataSource} (a real pool) * <li>Apache's Commons DBCP offers {@code org.apache.commons.dbcp.BasicDataSource} (a real pool)
* </ul> * </ul>
* *
* <p>Typical usage in bootstrap code: * <p>Typical usage in bootstrap code:
@ -80,7 +83,8 @@ import org.springframework.util.ClassUtils;
*/ */
public class SimpleNamingContextBuilder implements InitialContextFactoryBuilder { public class SimpleNamingContextBuilder implements InitialContextFactoryBuilder {
/** An instance of this class bound to JNDI */ /** An instance of this class bound to JNDI. */
@Nullable
private static volatile SimpleNamingContextBuilder activated; private static volatile SimpleNamingContextBuilder activated;
private static boolean initialized = false; private static boolean initialized = false;
@ -93,13 +97,14 @@ public class SimpleNamingContextBuilder implements InitialContextFactoryBuilder
* @return the current SimpleNamingContextBuilder instance, * @return the current SimpleNamingContextBuilder instance,
* or {@code null} if none * or {@code null} if none
*/ */
@Nullable
public static SimpleNamingContextBuilder getCurrentContextBuilder() { public static SimpleNamingContextBuilder getCurrentContextBuilder() {
return activated; return activated;
} }
/** /**
* If no SimpleNamingContextBuilder is already configuring JNDI, * If no SimpleNamingContextBuilder is already configuring JNDI,
* create and activate one. Otherwise take the existing activate * create and activate one. Otherwise take the existing activated
* SimpleNamingContextBuilder, clear it and return it. * SimpleNamingContextBuilder, clear it and return it.
* <p>This is mainly intended for test suites that want to * <p>This is mainly intended for test suites that want to
* reinitialize JNDI bindings from scratch repeatedly. * reinitialize JNDI bindings from scratch repeatedly.
@ -107,17 +112,18 @@ public class SimpleNamingContextBuilder implements InitialContextFactoryBuilder
* to control JNDI bindings * to control JNDI bindings
*/ */
public static SimpleNamingContextBuilder emptyActivatedContextBuilder() throws NamingException { public static SimpleNamingContextBuilder emptyActivatedContextBuilder() throws NamingException {
if (activated != null) { SimpleNamingContextBuilder builder = activated;
if (builder != null) {
// Clear already activated context builder. // Clear already activated context builder.
activated.clear(); builder.clear();
} }
else { else {
// Create and activate new context builder. // Create and activate new context builder.
SimpleNamingContextBuilder builder = new SimpleNamingContextBuilder(); builder = new SimpleNamingContextBuilder();
// The activate() call will cause an assignment to the activated variable. // The activate() call will cause an assignment to the activated variable.
builder.activate(); builder.activate();
} }
return activated; return builder;
} }
@ -138,12 +144,10 @@ public class SimpleNamingContextBuilder implements InitialContextFactoryBuilder
logger.info("Activating simple JNDI environment"); logger.info("Activating simple JNDI environment");
synchronized (initializationLock) { synchronized (initializationLock) {
if (!initialized) { if (!initialized) {
if (NamingManager.hasInitialContextFactoryBuilder()) { Assert.state(!NamingManager.hasInitialContextFactoryBuilder(),
throw new IllegalStateException(
"Cannot activate SimpleNamingContextBuilder: there is already a JNDI provider registered. " + "Cannot activate SimpleNamingContextBuilder: there is already a JNDI provider registered. " +
"Note that JNDI is a JVM-wide service, shared at the JVM system class loader level, " + "Note that JNDI is a JVM-wide service, shared at the JVM system class loader level, " +
"with no reset option. As a consequence, a JNDI provider must only be registered once per JVM."); "with no reset option. As a consequence, a JNDI provider must only be registered once per JVM.");
}
NamingManager.setInitialContextFactoryBuilder(this); NamingManager.setInitialContextFactoryBuilder(this);
initialized = true; initialized = true;
} }
@ -192,7 +196,8 @@ public class SimpleNamingContextBuilder implements InitialContextFactoryBuilder
* @see SimpleNamingContext * @see SimpleNamingContext
*/ */
@Override @Override
public InitialContextFactory createInitialContextFactory(Hashtable<?,?> environment) { @SuppressWarnings("unchecked")
public InitialContextFactory createInitialContextFactory(@Nullable Hashtable<?,?> environment) {
if (activated == null && environment != null) { if (activated == null && environment != null) {
Object icf = environment.get(Context.INITIAL_CONTEXT_FACTORY); Object icf = environment.get(Context.INITIAL_CONTEXT_FACTORY);
if (icf != null) { if (icf != null) {
@ -212,22 +217,16 @@ public class SimpleNamingContextBuilder implements InitialContextFactoryBuilder
"Specified class does not implement [" + InitialContextFactory.class.getName() + "]: " + icf); "Specified class does not implement [" + InitialContextFactory.class.getName() + "]: " + icf);
} }
try { try {
return (InitialContextFactory) icfClass.newInstance(); return (InitialContextFactory) ReflectionUtils.accessibleConstructor(icfClass).newInstance();
} }
catch (Throwable ex) { catch (Throwable ex) {
throw new IllegalStateException("Cannot instantiate specified InitialContextFactory: " + icf, ex); throw new IllegalStateException("Unable to instantiate specified InitialContextFactory: " + icf, ex);
} }
} }
} }
// Default case... // Default case...
return new InitialContextFactory() { return env -> new SimpleNamingContext("", this.boundObjects, (Hashtable<String, Object>) env);
@Override
@SuppressWarnings("unchecked")
public Context getInitialContext(Hashtable<?,?> environment) {
return new SimpleNamingContext("", boundObjects, (Hashtable<String, Object>) environment);
}
};
} }
} }

View File

@ -199,7 +199,7 @@ public abstract class ObjectUtils {
/** /**
* Check whether the given array of enum constants contains a constant with the given name, * Check whether the given array of enum constants contains a constant with the given name,
* ignoring case when determining a match. * ignoring case when determining a match.
* @param enumValues the enum values to check, typically the product of a call to MyEnum.values() * @param enumValues the enum values to check, typically obtained via {@code MyEnum.values()}
* @param constant the constant name to find (must not be null or empty string) * @param constant the constant name to find (must not be null or empty string)
* @return whether the constant has been found in the given array * @return whether the constant has been found in the given array
*/ */
@ -209,15 +209,14 @@ public abstract class ObjectUtils {
/** /**
* Check whether the given array of enum constants contains a constant with the given name. * Check whether the given array of enum constants contains a constant with the given name.
* @param enumValues the enum values to check, typically the product of a call to MyEnum.values() * @param enumValues the enum values to check, typically obtained via {@code MyEnum.values()}
* @param constant the constant name to find (must not be null or empty string) * @param constant the constant name to find (must not be null or empty string)
* @param caseSensitive whether case is significant in determining a match * @param caseSensitive whether case is significant in determining a match
* @return whether the constant has been found in the given array * @return whether the constant has been found in the given array
*/ */
public static boolean containsConstant(Enum<?>[] enumValues, String constant, boolean caseSensitive) { public static boolean containsConstant(Enum<?>[] enumValues, String constant, boolean caseSensitive) {
for (Enum<?> candidate : enumValues) { for (Enum<?> candidate : enumValues) {
if (caseSensitive ? if (caseSensitive ? candidate.toString().equals(constant) :
candidate.toString().equals(constant) :
candidate.toString().equalsIgnoreCase(constant)) { candidate.toString().equalsIgnoreCase(constant)) {
return true; return true;
} }
@ -228,7 +227,7 @@ public abstract class ObjectUtils {
/** /**
* Case insensitive alternative to {@link Enum#valueOf(Class, String)}. * Case insensitive alternative to {@link Enum#valueOf(Class, String)}.
* @param <E> the concrete Enum type * @param <E> the concrete Enum type
* @param enumValues the array of all Enum constants in question, usually per Enum.values() * @param enumValues the array of all Enum constants in question, usually per {@code Enum.values()}
* @param constant the constant to get the enum value of * @param constant the constant to get the enum value of
* @throws IllegalArgumentException if the given constant is not found in the given array * @throws IllegalArgumentException if the given constant is not found in the given array
* of enum values. Use {@link #containsConstant(Enum[], String)} as a guard to avoid this exception. * of enum values. Use {@link #containsConstant(Enum[], String)} as a guard to avoid this exception.
@ -239,9 +238,8 @@ public abstract class ObjectUtils {
return candidate; return candidate;
} }
} }
throw new IllegalArgumentException( throw new IllegalArgumentException("Constant [" + constant + "] does not exist in enum type " +
String.format("constant [%s] does not exist in enum type %s", enumValues.getClass().getComponentType().getName());
constant, enumValues.getClass().getComponentType().getName()));
} }
/** /**

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2016 the original author or authors. * Copyright 2002-2018 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -20,30 +20,24 @@ import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import static org.junit.Assert.*; import static org.junit.Assert.*;
/** /**
* Test suite for {@link FastByteArrayOutputStream} * Test suite for {@link FastByteArrayOutputStream}.
*
* @author Craig Andrews * @author Craig Andrews
*/ */
public class FastByteArrayOutputStreamTests { public class FastByteArrayOutputStreamTests {
private static final int INITIAL_CAPACITY = 256; private static final int INITIAL_CAPACITY = 256;
private FastByteArrayOutputStream os; private final FastByteArrayOutputStream os = new FastByteArrayOutputStream(INITIAL_CAPACITY);;
private byte[] helloBytes; private final byte[] helloBytes = "Hello World".getBytes(StandardCharsets.UTF_8);;
@Before
public void setUp() throws Exception {
this.os = new FastByteArrayOutputStream(INITIAL_CAPACITY);
this.helloBytes = "Hello World".getBytes("UTF-8");
}
@Test @Test

View File

@ -45,6 +45,7 @@ public class ObjectUtilsTests {
@Rule @Rule
public final ExpectedException exception = ExpectedException.none(); public final ExpectedException exception = ExpectedException.none();
@Test @Test
public void isCheckedException() { public void isCheckedException() {
assertTrue(ObjectUtils.isCheckedException(new Exception())); assertTrue(ObjectUtils.isCheckedException(new Exception()));
@ -807,7 +808,8 @@ public class ObjectUtilsTests {
assertThat(ObjectUtils.caseInsensitiveValueOf(Tropes.values(), "BAR"), is(Tropes.BAR)); assertThat(ObjectUtils.caseInsensitiveValueOf(Tropes.values(), "BAR"), is(Tropes.BAR));
exception.expect(IllegalArgumentException.class); exception.expect(IllegalArgumentException.class);
exception.expectMessage(is("constant [bogus] does not exist in enum type org.springframework.util.ObjectUtilsTests$Tropes")); exception.expectMessage(
is("Constant [bogus] does not exist in enum type org.springframework.util.ObjectUtilsTests$Tropes"));
ObjectUtils.caseInsensitiveValueOf(Tropes.values(), "bogus"); ObjectUtils.caseInsensitiveValueOf(Tropes.values(), "bogus");
} }
@ -818,6 +820,6 @@ public class ObjectUtilsTests {
} }
enum Tropes { FOO, BAR, baz } enum Tropes {FOO, BAR, baz}
} }

View File

@ -104,7 +104,7 @@ public class SimpleNamingContextBuilder implements InitialContextFactoryBuilder
/** /**
* If no SimpleNamingContextBuilder is already configuring JNDI, * If no SimpleNamingContextBuilder is already configuring JNDI,
* create and activate one. Otherwise take the existing activate * create and activate one. Otherwise take the existing activated
* SimpleNamingContextBuilder, clear it and return it. * SimpleNamingContextBuilder, clear it and return it.
* <p>This is mainly intended for test suites that want to * <p>This is mainly intended for test suites that want to
* reinitialize JNDI bindings from scratch repeatedly. * reinitialize JNDI bindings from scratch repeatedly.
@ -226,7 +226,7 @@ public class SimpleNamingContextBuilder implements InitialContextFactoryBuilder
} }
// Default case... // Default case...
return environment1 -> new SimpleNamingContext("", this.boundObjects, (Hashtable<String, Object>) environment1); return env -> new SimpleNamingContext("", this.boundObjects, (Hashtable<String, Object>) env);
} }
} }