Какова роль ClassOutline / JClass / CClass в CodeModel?
Мой вопрос касается написания плагинов JAXB, в частности кодовой модели JAXB.
Какова роль ClassOutline
(и это спутники) и JClass
(и товарищи) и CClass
(и товарищи)? При просмотре списка классов в соответствующих пакетах не ясно, что такое курица, а что яйцо.
Моя интерпретация такова, что CClass
(CPropertyInfo
, CEnumConstant
,...) создаются XJC при первом черновом разборе XSD. Затем происходит какое-то волшебство, и эта модель превращается в JClass
(JFieldVar
, JEnumConstant
,...) и во время этого преобразования применяются настройки. После этого плагины запускаются. ClassOutline
используется в качестве моста между этими двумя моделями. В целом выглядит очень сложно.
С помощью этих параллельных моделей я считаю, что одну и ту же информацию можно получить несколькими способами. Например, тип поля класса:
JClass#fields()
→JFieldVar#type
→JType
CClassInfo#getProperties()
→CPropertyInfo#baseType
→JType
Я ищу подробное объяснение жизненного цикла вышеупомянутых моделей. Благодарю.
2 ответа
О, о, кто-то интересуется внутренностями XJC. Я мог бы быть чем-то полезен, так как я, вероятно, разработал больше плагинов JAXB, чем кто-либо другой (см., Например, Основы JAXB2)
Хорошо, давайте начнем. В XJC компилятор схемы делает примерно следующее
- Разбирает схему
- Создает модель схемы (CClass, CPropertyInfo и т. Д.)
- Создает контур (ClassOutline, FieldOutline и т. Д.)
- Визуализирует модель кода (JClass, JDefinedClass, JMethod и т. Д.)
- Записывает физический код (например, файлы Java на диске)
Давайте начнем с последних двух.
Я надеюсь, что файлы Java не нуждаются в объяснении.
Кодовая модель также очень проста для родственников. Это API, который можно использовать для программного создания кода Java. Вместо этого вы можете использовать конкатенацию строк, но она гораздо более подвержена ошибкам. С CodeModel вы почти гарантированно получите хотя бы грамматически правильный Java-код. Поэтому я надеюсь, что эта часть также ясна. (Кстати, мне очень нравится CodeModel. Недавно я написал JavaScript Code Model, основанную на идеях CodeModel.)
Давайте теперь посмотрим на "модель" и "контур". Модель является результатом анализа входящей схемы. Он моделирует конструкции входящей схемы, в основном в терминах "классов", которые соответствуют сложным типам, и "свойств", которые соответствуют элементам, атрибутам и значениям (например, когда у вас есть сложный тип с простым содержимым).
Модель следует понимать как логическую конструкцию, близкую к XML и схеме. Как таковой, он просто описывает типы и свойства, которые они имеют. Это, безусловно, намного сложнее, чем то, как я описываю это, есть все виды исключений и предостережений - начиная с типов карточек (xsd:any), групп подстановок, перечислений, встроенных типов и так далее.
Довольно интересно, родной брат Model
является RuntimeTypeInfoSetImpl
который используется JAXB во время выполнения. Так что это также тип модели, который, однако, анализируется не по схеме XML, а по аннотациям JAXB в классах. Концепция такая же. Обе модели и RuntimeTypeInfoSetImpl
реализовать TypeInfoSet
интерфейс, который является супер-конструкцией. Проверьте интерфейсы как ClassInfo
а также PropertyInfo
- они имеют реализацию как во время компиляции (CClassInfo
а также CPropertyInfo
в XJC) и во время выполнения (RuntimeClassInfoImpl
и т. д. для JAXB RI).
Итак, когда XJC проанализировал и проанализировал схему, вы получили Model
, это Model
не могу произвести код еще. Есть действительно разные стратегии создания кода. Вы можете генерировать только аннотированные классы или вы можете генерировать пару интерфейса / реализации класса, как в JAXB 1. На самом деле создание всего кода не является задачей модели. Более того, существует ряд аспектов, которые имеют отношение к физической природе кода Java, но не имеют отношения к модели. Например, вы должны сгруппировать классы в пакеты. Это обусловлено системой упаковки Java, а не свойствами самой модели.
И именно здесь в игру вступают очертания. Вы можете видеть контуры как шаг между моделью схемы и моделью кода. Вы можете рассматривать схемы как фабрики для элементов модели кода, отвечающие за организацию кода и генерацию JDefinedClass
из CClassInfo
s.
Итак, вы правы, это действительно очень сложно. Я не сотрудник Sun/Oracle, я не проектировал это (хотя я знаю человека, который сделал это, и очень уважаю его). Я могу предположить несколько причин для определенных дизайнерских решений, например:
- Используйте одни и те же интерфейсы для моделей времени компиляции и выполнения
- Разрешить разные стратегии генерации кода
- Разрешить плагинам манипулировать созданной моделью
Я согласен, что этот дизайн очень сложный, но у него есть свои причины. Одним из доказательств этого является то, что на самом деле можно было создать генератор сопоставлений для сопоставлений XML-JavaScript - в основном на тех же моделях. Мне просто пришлось заменить генерацию кода, оставив нетронутым анализ схемы. (См. Jsonix для этого.)
Хорошо, надеюсь, я пролил некоторый свет на то, почему вещи в XJC такие, какие они есть. Удачи с этими API, они не прямолинейны. Не стесняйтесь проверять существующий код с открытым исходным кодом, есть много доступных примеров.
пс. На самом деле всегда хотел написать это.:)
(Это чтобы ответить на ваши дальнейшие вопросы.)
Да, можно проверить настройки. Вот класс, который я использую для доступа к настройкам.
Хитрость в том, что ссылочные свойства не имеют собственных настроек, настройки помещаются в свойствах ссылочных элементов.
public static CCustomizations getCustomizations(
final CPropertyInfo propertyInfo) {
final CCustomizations main = new CCustomizations(
propertyInfo.getCustomizations());
final Collection<CCustomizations> elementCustomizations = propertyInfo
.accept(new CPropertyVisitor<Collection<CCustomizations>>() {
public Collection<CCustomizations> onAttribute(
CAttributePropertyInfo info) {
return Collections.emptyList();
}
public Collection<CCustomizations> onElement(
CElementPropertyInfo arg0) {
return Collections.emptyList();
}
public Collection<CCustomizations> onReference(
CReferencePropertyInfo info) {
final List<CCustomizations> elementCustomizations = new ArrayList<CCustomizations>(
info.getElements().size());
for (CElement element : info.getElements()) {
if (!(element instanceof CElementInfo && ((CElementInfo) element)
.hasClass())) {
elementCustomizations.add(element
.getCustomizations());
}
}
return elementCustomizations;
}
public Collection<CCustomizations> onValue(
CValuePropertyInfo arg0) {
return Collections.emptyList();
};
});
CCustomizations customizations = main;
for (CCustomizations e : elementCustomizations) {
main.addAll(e);
}
return customizations;
}
Я бы сказал, что users@jaxb.java.net - хорошее место для таких обсуждений.