1、概述
其作为ContentParser的注册器,用于统一管理 ContextParser。
2、NamedXContentRegistry
与NamedWriteableRegistry类似
其成员有
成员 | 说明 |
Map<Class<?>, Map<String, Entry>> registry | 注册器 |
Map<Class<?>, Map<String, Entry>> compatibleRegistry | 兼容的注册器 |
2.1 NamedXContentRegistry.Entry
成员包含
成员 | 说明 |
Class<?> categoryClass | 实体需要读取的类 |
ParseField name | 类型类内可以唯一标识的名称 |
ContextParser<Object, ?> parser | 内容解析器 |
2.2 构造函数
public NamedXContentRegistry(List<Entry> entries, List<Entry> compatibleEntries) {
this.registry = unmodifiableMap(getRegistry(entries));
this.compatibleRegistry = unmodifiableMap(getCompatibleRegistry(compatibleEntries));
}
初始化registry和compatibleRegistry两个成员。
初始化registry是通过调用getRegistry实现初始化。
private Map<Class<?>, Map<String, Entry>> getRegistry(List<Entry> entries){
if (entries.isEmpty()) {
return emptyMap();
}
entries = new ArrayList<>(entries);
entries.sort((e1, e2) -> e1.categoryClass.getName().compareTo(e2.categoryClass.getName()));
Map<Class<?>, Map<String, Entry>> registry = new HashMap<>();
Map<String, Entry> parsers = null;
Class<?> currentCategory = null;
for (Entry entry : entries) {
if (currentCategory != entry.categoryClass) {
if (currentCategory != null) {
// we've seen the last of this category, put it into the big map
registry.put(currentCategory, unmodifiableMap(parsers));
}
parsers = new HashMap<>();
currentCategory = entry.categoryClass;
}
for (String name : entry.name.getAllNamesIncludedDeprecated()) {
Object old = parsers.put(name, entry);
if (old != null) {
throw new IllegalArgumentException("NamedXContent [" + currentCategory.getName() + "][" + entry.name + "]" +
" is already registered for [" + old.getClass().getName() + "]," +
" cannot register [" + entry.parser.getClass().getName() + "]");
}
}
}
// handle the last category
registry.put(currentCategory, unmodifiableMap(parsers));
return registry;
}
与NamedWriteableRegistry的初始化相似。先根据Entry中的categoryClass的名称排序,然后依次放入registry中。
初始化compatibleRegistry是通过调用getCompatibleRegistry实现初始化。
private Map<Class<?>, Map<String, Entry>> getCompatibleRegistry(List<Entry> compatibleEntries) {
Map<Class<?>, Map<String, Entry>> compatibleRegistry = new HashMap<>(registry);
List<Entry> unseenEntries = new ArrayList<>();
compatibleEntries.forEach(entry -> {
Map<String, Entry> parsers = compatibleRegistry.get(entry.categoryClass);
if (parsers == null) {
unseenEntries.add(entry);
} else {
Map<String, Entry> parsersCopy = new HashMap<>(parsers);
for (String name : entry.name.getAllNamesIncludedDeprecated()) {
parsersCopy.put(name, entry); //override the parser for the given name
}
compatibleRegistry.put(entry.categoryClass, parsersCopy);
}
}
);
compatibleRegistry.putAll(getRegistry(unseenEntries));
return compatibleRegistry;
}
其会将compatibleEntries中不在registry中的也添加上,同时会将过时的name与Entry的对应关系添加
2.3 parseNamedObject
解析内容。根据categoryClass和name从registry或者compatibleRegistry得到对应的ContextParser,然后使用parsere来解析context。
public <T, C> T parseNamedObject(Class<T> categoryClass, String name, XContentParser parser, C context) throws IOException {
Map<String, Entry> parsers = parser.getRestApiVersion() == RestApiVersion.minimumSupported() ?
compatibleRegistry.get(categoryClass) : registry.get(categoryClass);
if (parsers == null) {
if (registry.isEmpty()) {
// The "empty" registry will never work so we throw a better exception as a hint.
throw new XContentParseException("named objects are not supported for this parser");
}
throw new XContentParseException("unknown named object category [" + categoryClass.getName() + "]");
}
Entry entry = parsers.get(name);
if (entry == null) {
throw new NamedObjectNotFoundException(parser.getTokenLocation(), "unknown field [" + name + "]", parsers.keySet());
}
if (false == entry.name.match(name, parser.getDeprecationHandler())) {
/* Note that this shouldn't happen because we already looked up the entry using the names but we need to call `match` anyway
* because it is responsible for logging deprecation warnings. */
throw new XContentParseException(parser.getTokenLocation(),
"unable to parse " + categoryClass.getSimpleName() + " with name [" + name + "]: parser didn't match");
}
return categoryClass.cast(entry.parser.parse(parser, context));
}