2010-12-20 2 views
4

Извините, длина этого вопроса. Я новичок в Java, и я столкнулся с чем-то, что действительно меня колотило. Я так новичок в Java, что еще не знаю всей терминологии, поэтому, пожалуйста, несите меня; У меня около 3 лет опыта работы с PHP (в основном процедурный, а не OO), но очень мало Java. Я также знаю, что отладка с System.out.println - это неправильный способ сделать это, но он работает, и это то, к чему я привык (вставьте здесь шутки о программистах PHP, если нужно). Я все еще пытаюсь понять, как использовать отладчик NetBeans.Отражение Java не согласуется с объявлением метода

Я работаю над добавлением функции в веб-приложение, использующее Struts (1.x). Проблема, с которой я сталкиваюсь, заключается в том, что объявлен метод, когда требуется передать String, но при этом Reflection на этом методе говорит, что он хочет String [] (массив строк). Я ограничен тем, что не могу внести существенные структурные изменения в приложение, и, конечно же, я должен убедиться, что я ничего не нарушаю в приложении, которое сейчас работает, поэтому я пытаюсь сделать свой изменения в контексте того, что уже существует. Таким образом, к проблеме ...

Вот где метод объявлен (много много линий, вырезанных из них, чтобы показать только то, что я надеюсь, являются соответствующими битами):

AEReportBean.java:

public class AEReportBean { 
    private String selectedDownloadFields = null; 

    public String getSelectedDownloadFields() { 
     return selectedDownloadFields; 
    } 

    // Note that there is no overloading of this function anywhere, this is the only declaration. 
    public void setSelectedDownloadFields(String selectedDownloadFields) { 
     this.selectedDownloadFields = selectedDownloadFields; 
    } 
} 

Когда пользователь нажимает кнопку Submit на форме, он получает обрабатываются AEReportSubmitAction.java:

public class AEReportSubmitAction extends BaseAction { 
    public ActionForward doExecute(
      ActionMapping mapping, 
      ActionForm form, 
      HttpServletRequest request, 
      HttpServletResponse response 
     ) throws Exception { 
     // This works fine, the paramater is getting passed in the request: 
     System.out.println("URL parameter: " + request.getParameter("selectedDownloadFields"); 

     AEReportBean bean = new AEReportBean(request.getLocale(), 0); 

     PropertyUtil.setAllFromRequest(request, bean); 
     // This prints "Null", meaning the setAllFromRequest line above is failing to set this property. 
     System.out.println("AEReportSubmitAction.java - bean.getSelectedDownloadFields() after setAllFromRequest: " + bean.getSelectedDownloadFields()); 
    } 
} 

PropertyUtil.setAllFromRequest(), где магия, и реальная проблема, хап ручки:

public class PropertyUtil { 
    /** 
    * Takes all the parameters from the request object and if there's a matching 
    * mutator method in the bean, sets it 
    */ 
    static public void setAllFromRequest(ServletRequest request, Object out) { 
     // Iterate through all the request parameter names and try to set each one. 
     for (Enumeration parameterNames = request.getParameterNames(); parameterNames.hasMoreElements();) { 
      String name = (String) parameterNames.nextElement(); 
      try { 
       PropertyUtil.setSimpleProperty(out, name, request.getParameter(name)); 
      } 
      catch (Exception e) { 
       log.info("Exception while setting properties from the Request. parameterName=" + name, e); 
      } 
     } 
    } 

    /** 
    * Sets the property from an object using the object's mutator method. 
    * Assumes naming conventions for accessor methods 
    * @param bean the object to get the property from 
    * @param property the name of the property to obtain 
    * @param newProperty the object to set 
    */ 
    // NOTE: This just seems to be a wrapper for the method below it... 
    static public void setSimpleProperty(Object bean, String property, Object newProperty) throws Exception { 
     PropertyUtil.setSimpleProperty(bean, property, newProperty, null); 
    } 

    /** 
    * Sets the property from an object using the object's mutator method. 
    * Assumes naming conventions for accessor methods 
    * @param bean the object to get the property from 
    * @param property the name of the property to obtain 
    * @param newProperty the object to set 
    */ 
    static public void setSimpleProperty(Object bean, String property, Object newProperty, Class type) throws Exception { 
     // Capitalize the first letter in the property and append "set" to the front 
     String methodName = "set" + property.substring(0, 1).toUpperCase() + property.substring(1); 
     Method method; 

     Class[] parameters; 

     // If the Type was passed in when this method was called, simply add it to the Class array. 
     if (type != null) { 
      parameters = new Class[]{type}; 
     } 
     // If the Type was not specified, determine the Type's class by calling getClass() on it; that class will be used below to call the appropriate setter method. 
     else { 
      parameters = new Class[]{newProperty.getClass()}; 
     } 

     // Here's the reflection problem... 
     // Iterate through all the methods in the bean. If the method is named "setSelectedDownloadFields", print out some info about it. 
     for (Method m : bean.getClass().getMethods()) { 
      if (m.getName().equals("setSelectedDownloadFields")) { 
       // newProperty is the incoming data that ultimately comes from the HTML form field. 
       System.out.println("newProperty.getClass(): " + newProperty.getClass()); // Prints "class java.lang.String" 

        // Added for Cameron Skinner in comments. 
        System.out.println("m.toGenericString: " + m.toGenericString()); // Prints "public void com.[company deleted].bean.AEReportBean.setSelectedDownloadFields(java.lang.String[])" 

       System.out.println("m.getName(): " + m.getName()); // Prints "setSelectedDownloadFields" 
       System.out.println("parameters:"); 
       for (Class c : m.getParameterTypes()) { 
        System.out.println("--c.getCanonicalName(): " + c.getCanonicalName()); // Prints "java.lang.String[]" 
        System.out.println("--c.getName(): " + c.getName()); // Prints "[Ljava.lang.String;" 
       } 
      } 
     } 


     // And here's where it fails... 
     try { 
      System.out.println("bean.getClass(): " + bean.getClass()); // Prints "class com.[company deleted].bean.AEReportBean" 
      System.out.println("methodName: " + methodName); // Prints "setSelectedDownloadFields" 
      System.out.println("for (Class p : parameters):"); 
      for (Class p : parameters) { 
       System.out.println("--p.getCanonicalName(): " + p.getCanonicalName()); // Prints "java.lang.String" 
      } 

      // Here it looks for a method called, effectively, AEReportBean.setSelectedDownloadFields(String s), but above we see that reflection is showing it as AEReportBean.setSelectedDownloadFields(String[] s), so the try block fails. 
      method = bean.getClass().getMethod(methodName, parameters); 
     } 
     catch (NoSuchMethodException e) { 
      // All lines below here also fail until it bombs out with the exception at the bottom... 

      // If no method can be found, then see if it's a primitive type that 
      // has been wrapped 
      Class valueClass = newProperty.getClass(); 
      //System.out.println("valueClass.toString() = " + valueClass.toString()); 
      try { 
       if (valueClass.equals(Integer.class)) { 
        method = bean.getClass().getMethod(methodName, new Class[]{int.class}); 
       } 
       else if (valueClass.equals(Double.class)) { 
        method = bean.getClass().getMethod(methodName, new Class[]{double.class}); 
       } 
       else if (valueClass.equals(Long.class)) { 
        method = bean.getClass().getMethod(methodName, new Class[]{long.class}); 
       } 
       else if (valueClass.equals(Float.class)) { 
        method = bean.getClass().getMethod(methodName, new Class[]{float.class}); 
       } 
       else { 
        throw new Exception(e.getMessage()); 
       } 
      } 
      catch (NoSuchMethodException ex) { 
       throw new Exception(ex.getMessage()); 
      } 
     } 

     // If it had gotten to this point, it would call the method with the appropriate parameters, and the property would be set. 
     try { 
      // Now execute the method 
      method.invoke(bean, new Object[]{newProperty}); 
     } 
     catch (Exception ex) { 
      throw new Exception(ex.getMessage()); 
     } 
    } 
} 

Я действительно не знаю, чего мне здесь не хватает, но должно быть что-то. Другие элементы HTML-формы на одной странице работают отлично. Пожалуйста, дайте мне знать, если вам нужна дополнительная информация. Благодаря!

+0

Как выглядит struts-config.xml? – stjohnroe

+0

Можете ли вы добавить вызов 'm.toGenericString()' внутри вашего 'for (Метод m: bean.getClass(). GetMethods()) {if (m.getName(). Equals (" setSelectedDownloadFields ")) {' цикл? Мне было бы интересно посмотреть, что он говорит. –

+0

@stjohnroe: Соответствующие линии распорок-config.xml: <действие путь = тип "/ aeReportSubmit" = "ком [компания удален] .actions.AEReportSubmitAction"> \t <вперед имя = "backToList" путь =» /aeReportList.do "/> \t -> \t \t (Извините, форматирование кода, похоже, не работает в комментариях ...) – Sam

ответ

4

Результаты кода не лежат. Это в основном говорит о том, что класс не тот, которого вы ожидаете. У вас несколько классов AEReportBean различных версий в пути к классу вашего проекта, возможно, в разных пакетах, а неверный импортирован или имеет приоритет при загрузке классов. Сделайте поиск типа/класса в Netbeans, чтобы найти все классы по заданному имени в пути к классам (я не делаю Netbeans, но в Eclispe это Ctrl + Shift + T, эквивалент Netbeans, вероятно, Alt + Shift + O) ,

Update: другая возможная причина в том, что Netbeans не построить проект автоматически сохранить в исходном файле (интегрированная среда должна создать/обновить .class файлы во время сборки). Посмотрите где-нибудь в настройках.

+0

Я дважды проверю это, когда буду работать завтра, но метод selectedDownloadFields был добавлен мной, и я только поместил его в один файл. Я выполнил полный поиск текста во всей проверке SVN, чтобы убедиться потому что перегрузка была первой, о чем я думал, но я еще раз проверю. Я знаю, что компьютеры всегда делают то, что вы говорите, а не то, что вы имеете в виду, поэтому где-то я должен сказать это неправильно, но, черт возьми, если я смогу где ... Я буду обновлять завтра результаты. – Sam

+0

+1 для BalusC, попробуйте изменить AEReportBean в некотором роде, чтобы убедиться, что это то, что ваше приложение видит ... – pgras

+0

ОК, я добавил пару System.out .println() вызывает AEReportBean.java (один в конструкторе и два в других сеттерах, которые должны вызываться вместе с setSelectedDownloadFields() и которые работают правильно). Ни один из отпечатков не появился на выходе ... Но я сделал полный текстовый поиск для «aereportbean», и он появляется только в 5 файлах, включая AEReportBean.java. Ни один из других файлов, в которых он находится, имеет ничего, кроме собственных классов; насколько я могу судить, AEReportBean не объявлен нигде. Те же результаты поиска в NetBeans. Любые идеи, почему мои printlns не появляются? – Sam

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