Что может вызвать сбой HashMap containsKey() с String в качестве ключа?
Я полностью смущен этим. Я запускаю полный пакет комплексных тестов. Вот соответствующий общий код, который используется рядом тестов JUnit:
private static Map<String, JAXBContext> jaxbContexts =
new HashMap<String, JAXBContext>();
private synchronized JAXBContext getJAXBContext(Class clazz) throws JAXBException {
JAXBContext context = null;
if (jaxbContexts.containsKey(clazz.getName())) {
context = jaxbContexts.get(clazz.getName());
} else {
context = JAXBContext.newInstance(clazz);
System.out.println("Created new context for '" + clazz.getName() + "'");
jaxbContexts.put(clazz.getName(), context);
}
return context;
}
Вывод консоли из прогона JUnit включает следующие две последовательные записи:
Created new context for 'com.somecompany.xmlschema.providepensionpaymentinfo.Interface'
Created new context for 'com.somecompany.xmlschema.providepensionpaymentinfo.Interface'
Что мне не хватает? Почему сделал jaxbContexts.containsKey()
не работает в этом случае для ключа на основе строки, в отличие от 46 других случаев во время выполнения JUnit? Мы не проводим наши тесты параллельно, но мы используем Аспекты, если это имеет значение.
5 ответов
Отладьте его и убедитесь, что класс, содержащий этот метод getJAXBContext(), создается только один раз (проверяя, имеет ли он одинаковый идентификатор памяти в режиме отладки для каждого вызова). Если это разные экземпляры, ключевое слово synchronized будет блокировать разные блокировки, и они будут использовать разные карты.
Лично я не стал бы беспокоиться с содержанием ключа.
String name = clazz.getName();
context = jaxbContexts.get(name);
if (context == null) {
context = JAXBContext.newInstance(clazz);
System.out.println("Created new context for '" + name + "'");
jaxbContexts.put(name, context);
}
В Map нет ничего особенного, содержащего строки в качестве ключей. Просто замените println на new Exception().printStackTrace()
и вы увидите, что происходит. Вы можете создавать два экземпляра класса, содержащего карту, или что-то еще.
За исключением гонки... Но вы говорите, что вы не запускаете вещи параллельно...
Во всяком случае, я бы позвонил context = jaxbContexts.get(clazz.getName())
и проверено context
против null
,
Ах, и использовал сам класс в качестве ключа, потому что несколько классов могут иметь одно и то же имя (например, загрузчики классов)
Карта может быть Map<Class, JAXBContext>
вместо Map<String, JAXBContext>
для более легкого использования.