Что может вызвать сбой HashMap containsKey () с String в качестве ключа? - PullRequest
2 голосов
/ 20 января 2011

Я полностью сбит с толку этим.Я запускаю полный пакет комплексных тестов.Вот соответствующий общий код, который используется рядом тестов 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 ]

3 голосов
/ 20 января 2011

Отладьте его и убедитесь, что класс, содержащий этот метод getJAXBContext (), создается только один раз (проверяя, имеет ли он одинаковый идентификатор памяти в режиме отладки для каждого вызова). Если это разные экземпляры, ключевое слово synchronized будет блокироваться на разных блокировках, и они будут использовать разные карты.

1 голос
/ 20 января 2011

В Map нет ничего особенного, содержащего строки в качестве ключей.Просто замените println на new Exception().printStackTrace(), и вы увидите, что происходит.Возможно, вы создаете два экземпляра класса, содержащего карту, или что-то еще.

1 голос
/ 20 января 2011

Лично я не стал бы беспокоиться с содержанием ключа.

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);
}
0 голосов
/ 20 января 2011

Для удобства использования карта может быть Map<Class, JAXBContext> вместо Map<String, JAXBContext>.

0 голосов
/ 20 января 2011

За исключением гонки ... Но вы говорите, что не запускаете вещи параллельно ...

В любом случае, я бы назвал context = jaxbContexts.get(clazz.getName()) и проверил context против null.

Ах, и использовал сам класс в качестве ключа, потому что несколько классов могут иметь одинаковые имена (например, загрузчики классов)

...