Какова роль ClassOutline / JClass / CClass в CodeModel?

Мой вопрос касается написания плагинов JAXB, в частности кодовой модели JAXB.

Какова роль ClassOutline (и это спутники) и JClassтоварищи) и CClassтоварищи)? При просмотре списка классов в соответствующих пакетах не ясно, что такое курица, а что яйцо.

Моя интерпретация такова, что CClass (CPropertyInfo, CEnumConstant,...) создаются XJC при первом черновом разборе XSD. Затем происходит какое-то волшебство, и эта модель превращается в JClass (JFieldVar, JEnumConstant,...) и во время этого преобразования применяются настройки. После этого плагины запускаются. ClassOutline используется в качестве моста между этими двумя моделями. В целом выглядит очень сложно.

С помощью этих параллельных моделей я считаю, что одну и ту же информацию можно получить несколькими способами. Например, тип поля класса:

  • JClass#fields()JFieldVar#typeJType
  • CClassInfo#getProperties()CPropertyInfo#baseTypeJType

Я ищу подробное объяснение жизненного цикла вышеупомянутых моделей. Благодарю.

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 - хорошее место для таких обсуждений.

Другие вопросы по тегам