2017-01-12 1 views
0

У меня есть проект, который использует grails 2.2.4 и hibernate 3. Я переношу его на grails 3.2.4, который использует спящий режим 5. Я начал с создания проекта grails 3.2.4 с нуля, и теперь я медленно копирую мелкие фрагменты кода из старого проекта и получаю его работу. Сначала я только копировал свои классы User, UserRole и Role и получал весь поток входа в систему безопасности весны. Затем я скопировал оставшиеся объекты домена и попытался запустить мой проект. В моих объектах домена используются сопоставления GORM, а не аннотации JPA. Проект даже не запускается и получает следующее исключение при запуске (я привязан к публичному тексту, потому что содержимое слишком длинное для того, что позволяет переполнение стека).MappingException при переходе с Hibernate 3/Grails 2.2.4 на Hiberate 5/Grails 3.2.4

https://gist.github.com/schmickie/10522d3a2b8a66b6fb79f76e2af0fd72

Я сделал некоторые функции поиска в Интернете за ошибку и все, что я могу найти говорит, что это связано с проблемами с созданием композитных первичных ключей. Однако я не использую никаких составных первичных ключей. У кого-нибудь есть идеи, что происходит не так? Объекты домена, на которые ссылаются ошибки, Api и Method, показаны ниже.

class Api implements Serializable { 

    String name 
    boolean enabled 
    String apiVersion 
    String swaggerVersion 
    String resourcePath 
    String jsonData 
    boolean https = true 
    String regionSource 
    String contractName 
    String contractBasePath 

    Date dateCreated 
    Date lastUpdated 
    Date deprecationDate 

    static hasMany = [methods: Method, models: Model, apiServers: ApiServer] 

    static mapping = { 
     cache true 
    } 

    static constraints = { 
     name(nullable: false, blank: false) 
     enabled() 
     apiVersion(nullable: true, blank: true) 
     resourcePath(nullable: true, blank: true) 
     swaggerVersion(nullable: true, blank: true) 
     jsonData(type: 'text', nullable: true, blank: true) 
     dateCreated() 
     lastUpdated() 
     deprecationDate(nullable: true) 
     regionSource(nullable: true) 
     contractName(nullable: true) 
     contractBasePath(nullable: true) 
    } 

    public Method getMethod(String name) { 
     for (Method method : methods) { 
      if (method.name.equals(name)) { 
       return method 
      } 
     } 
     return null 
    } 
} 

class Method implements Serializable, Comparable<Method> { 

    String name 
    boolean enabled 
    String edgePath 
    HttpMethodEnum edgeHttpMethod 
    String servicePath 
    HttpMethodEnum serviceHttpMethod 
    String summary 
    String notes 
    boolean deprecatedMethod 
    String responseClass 
    SortedSet<EdgeParameter> edgeParameters 
    SortedSet<ServiceParameter> serviceParameters 
    Date dateCreated 
    Date lastUpdated 
    String publicResponseTransformScript 
    String baseResponseTransformScript 
    String regionFieldName 
    String platformFieldName 
    String apiKeyFieldName 
    String uriTransformScript 
    long cacheExpiry 

    static belongsTo = [api: Api] 
    static hasMany = [edgeParameters: EdgeParameter, serviceParameters: ServiceParameter, errorResponses: ApiErrorResponse] 


    static mapping = { 
     cache true 
     errorResponses sort: 'code', order: "asc" 
    } 

    static constraints = { 
     name(blank: false) 
     enabled() 
     edgePath(nullable: false, blank: false) 
     edgeHttpMethod(nullable: false, blank: false) 
     servicePath(nullable: false, blank: false) 
     serviceHttpMethod(nullable: false, blank: false) 
     summary(nullable: false, blank: false) 
     notes(nullable: true, blank: true) 
     deprecatedMethod() 
     responseClass(nullable: true, blank: true) 
     publicResponseTransformScript(nullable: true) 
     baseResponseTransformScript(nullable: true) 
     regionFieldName(nullable: true) 
     platformFieldName(nullable: true) 
     apiKeyFieldName(nullable: true) 
     uriTransformScript(nullable: true) 
     cacheExpiry(nullable: false, blank: true) 
    } 
} 
+0

Проблема связана ошибка при создании боба с именем «springSecurityUiInterceptor. Является ли это весной безопасности и весной безопасности ui плагинов, если это так можно отключить ui плагин в качестве теста? – Vahid

+0

Что заставляет вас думать, что это связано с фазой springSecurityUiInterceptor? Кстати, я уже опубликовал и принял свой собственный ответ ниже, выяснив это. Я представил PR для проекта grails, чтобы сделать сообщение об ошибках более ясным, и оно было объединено. – Schmick

+0

Я думаю, что это были журналы ошибок по этой ссылке gist на этой строке: 01/12/2017 11:17:37 PST WARN main AbstractApplicationContext: 550 - ошибка начинается с springSecurityUiInterceptor .. Но тогда это явно поспешный ответ и, похоже, немного похоже на то, что после того, как весенняя безопасность будет установлена, и любые ошибки возвращаются, похоже, связаны с весной безопасности, и новичок может подумать, что это весенняя безопасность, когда это были другие проблемы, но встроенные в рамках весенней безопасности – Vahid

ответ

0

Ну, я понял. Я сделал много шагов по инициализации hibernate/GORM. Я обнаружил, что проблема связана с несвязанным сопоставлением в том же классе. В классе Method есть другое отображение, показанное выше, которое называется errorResponses. Когда вызывается метод DefaultGrailsDomainClass.establishRelationshipForCollection, чтобы установить связь между классами Api и Method, он вызывает другой метод GrailsClassUtils.getPropertiesOfType. Этот класс выполняет итерацию по всем свойствам класса Method и пытается найти любые, тип которых соответствует типу ассоциации api. Вот реализация метода:

public static PropertyDescriptor[] getPropertiesOfType(Class<?> clazz, Class<?> propertyType) { 
    if (clazz == null || propertyType == null) { 
     return new PropertyDescriptor[0]; 
    } 

    Set<PropertyDescriptor> properties = new HashSet<PropertyDescriptor>(); 
    try { 
     for (PropertyDescriptor descriptor : BeanUtils.getPropertyDescriptors(clazz)) { 
      Class<?> currentPropertyType = descriptor.getPropertyType(); 
      if (isTypeInstanceOfPropertyType(propertyType, currentPropertyType)) { 
       properties.add(descriptor); 
      } 
     } 
    } 
    catch (Exception e) { 
     // if there are any errors in instantiating just return null for the moment 
     return new PropertyDescriptor[0]; 
    } 
    return properties.toArray(new PropertyDescriptor[properties.size()]); 
} 

Первое свойство находит это api свойство, которое проходит проверку isTypeInstanceOfPropertyType и добавляется к properties Set. Из-за плохо названного вспомогательного метода с именем getApiErrorResponse, вызов в BeanUtils.getPropertyDescriptors(clazz) включал поле, полученное в возвращаемой коллекции, apiErrorResponse. Однако в моем классе Method нет такого поля (имеется сопоставленная ассоциация с именем errorResponses, но ничего не называется apiErrorResponse). Таким образом, propertyType из PropertyDescriptor для этого несуществующего поля является нулевым. Затем, когда isTypeInstanceOfPropertyType вызывается с null значением для currentPropertyType, он генерирует исключение NullPointerException. Это приводит к тому, что метод getPropertiesOfType возвращает new PropertyDescriptor[0], как показано в предложении catch. Позже по этой строке этот отказ вернуть дескриптор свойства, который сопоставляется с api, вызывает неправильный тип отображения OneToOne, который должен быть сгенерирован для ассоциации, и что в сопоставлении отсутствует отображаемое поле.

В основном это был случай кода Грааля, не предоставляющего достаточной информации о том, что действительно пошло не так. Он молча подавил исключение NullPointerException, которое происходило в другом поле, а ошибка в этом другом поле вызывала неправильную инициализацию поля api. Это означало, что более поздние сообщения об ошибках были неправильно поданы, поскольку информация/конфигурация считались отсутствующими, когда это не было, что привело к очень запутанному инженеру.

Мое окончательное решение состояло в том, чтобы переместить вспомогательный метод getApiErrorResponse из класса Method и в MethodService. Обратите внимание, что наличие этого вспомогательного метода в моем доменном объекте отлично работало в моем старом проекте Grails (Grails 2.2.4 с Hiberate 3), с которого я переносился, поэтому это, по-видимому, новое поведение в последней версии Grails/GORM/Spring/Groovy предположить, что все методы get * отображаются в полях.Я не знаю, кто из них был бы виновником, но все они находятся на более новых версиях, чем мой старый проект.

Я также представил PR для grails-core, чтобы записывать полезные сообщения об ошибках, когда происходят эти виды исключений, вместо того, чтобы их молчаливо глотать.

https://github.com/grails/grails-core/pull/10400

Смежные вопросы