Почему Spring превращает мой объект в массив атрибутов? [Дубликат]

Хорошо, это начало длинной истории - сделано короткое «bort parsing командной строки в C ...

/**
* Helper function to parse the command line
* @param argc Argument Counter
* @param argv Argument Vector
* @param prog Program Instance Reference to fill with options
*/
bool parseCommandLine(int argc, char* argv[], DuplicateFileHardLinker* prog) {
  bool pathAdded = false;

  // iterate over all arguments...
  for ( int i = 1; i<argc; i++ ) {

    // is argv a command line option ?
    if ( argv[i][0] == '-' || argv[i][0] == '/' ) {

// ~~~~~~ Optionally Cut that part vvvvvvvvvvvvv for sake of simplicity ~~~~~~~
      // check for longer options
            if ( stricmp( &argv[i][1], "NoFileName"  ) == 0
              ||  strcmp( &argv[i][1], "q1"          ) == 0 ) {

        boNoFileNameLog = true;
      } else if ( strcmp( &argv[i][1], "FuckNow?"    ) == 0 ) {
          logInfo( "SECRET FOUND: Well - wow I'm glad ya ask me.");
      } else {

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Now here comes the main thing:
//
        // check for one char options
        while ( char option = *++argv[i] ) {

          switch ( option ) {
          case '?':
            // Show program usage

            logInfo(L"Options:");
            logInfo(L"  /q\t>Quite mode");
            logInfo(L"  /v\t>Verbose mode");
            logInfo(L"  /d\t>Debug mode");
            return false;

            // Log options
          case 'q':
            setLogLevel(LOG_ERROR);
            break;

          case 'v':
            setLogLevel(LOG_VERBOSE);
            break;

          case 'd':
            setLogLevel(LOG_DEBUG);
            break;

          default:
            logError(L"'%s' is an illegal command line option!"
                      "  Use /? to see valid options!", option);
            return false;
          } // switch one-char-option
        } //while one-char-options
      }  //else one vs longer options
    } // if isArgAnOption

// 
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^  So that's it! ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// What follows now is are some usefull extras...
//
    else {


      // the command line options seems to be a path...
      WCHAR tmpPath[MAX_PATH_LENGTH];
      mbstowcs(tmpPath, argv[i], sizeof(tmpPath));

      // check if the path is existing!
      //...

      prog->addPath(tmpPath); //Comment or remove to get a working example
      pathAdded = true;
    }
  }

  // check for parameters
  if ( !pathAdded ) {
    logError("You need to specify at least one folder to process!\n"
             "Use /? to see valid options!");
    return false;
  }

  return true;
}



int main(int argc, char* argv[]) {

  try {
    // parse the command line
    if ( !parseCommandLine(argc, argv, prog) ) {
      return 1; 
    }

// I know that sample is just to show how the nicely parse commandline Arguments
// So Please excuse more nice useful C-glatter that follows now...
  }
  catch ( LPCWSTR err ) {
    DWORD dwError = GetLastError();
    if ( wcslen(err) > 0 ) {
      if ( dwError != 0 ) {
        logError(dwError, err);
      }
      else {
        logError(err);
      }
    }
    return 2;
  }
}

#define LOG_ERROR               1
#define LOG_INFO                0
#define LOG_VERBOSE             -1
#define LOG_DEBUG               -2

/** Logging Level for the console output */
int logLevel = LOG_INFO;

void logError(LPCWSTR message, ...) {
  va_list argp;
  fwprintf(stderr, L"ERROR: ");
  va_start(argp, message);
  vfwprintf(stderr, message, argp);
  va_end(argp);
  fwprintf(stderr, L"\n");
}


void logInfo(LPCWSTR message, ...) {
  if ( logLevel <= LOG_INFO ) {
    va_list argp;
    va_start(argp, message);
    vwprintf(message, argp);
    va_end(argp);
    wprintf(L"\n");
  }
}

Обратите внимание, что эта версия также поддерживает комбинирующие аргументы:« Вместо записи / h / s -> / hs также будет работать.

Извините за то, что вы публиковали n-й человек здесь, однако я не был доволен всеми автономными версиями, которые я видел здесь. Хорошо, что либцы прекрасны. Поэтому, я бы предпочел использовать parseer option libUCW, Arg или Getopt над самодельными.

Обратите внимание, что вы можете изменить:

*++argv[i] -> (++argv*)[0] более длинный, но загадочный, но все же cryptic.

Хорошо, давайте сломаем его: 1. argv [i] -> получить доступ к i-му элементу в поле указателя argv-char

  1. ++ * .. . -> будет перенаправлять argv-указатель на один символ
  2. ... [0] -> будет следовать указателю, прочитав char
  3. ++ (...) ->

Так приятно, что в C ## указатели «умерли» - долго живут указатели !!!

]
41
задан Pranav C Balan 6 September 2016 в 16:47
поделиться

5 ответов

Решение для запросов JPQL

Это поддерживается для JPQL-запросов JPA и объяснено как часть спецификации JPA .

Шаг 1: Объявите простой класс bean

package com.path.to.class;

public class SurveyAnswerStatistics {
  private String answer;
  private Long   cnt;

  public SurveyAnswerStatistics(String answer, Long cnt) {
    this.answer = answer;
    this.count  = cnt;
  }
}

Шаг 2: Верните экземпляры bean-компонента из метода репозитория

@Query("SELECT " +
       "    new com.path.to.class.SurveyAnswerStatistics(v.answer, COUNT(v)) " +
       "FROM " +
       "    Survey v " +
       "GROUP BY " +
       "    v.answer")
List<SurveyAnswerStatistics> findSurveyCount();

Важные замечания

  1. Обязательно укажите полный путь к классу bean с именем пакета. Например, если класс bean называется MyBean и он находится в пакете com.path.to, то полный путь к компоненту будет com.path.to.MyBean. Просто предоставление MyBean не будет работать (если только класс bean не находится в пакете по умолчанию).
  2. Обязательно вызовите конструктор класса bean, используя ключевое слово new. SELECT new com.path.to.MyBean(...) будет работать, тогда как SELECT com.path.to.MyBean не будет.
  3. Обязательно передавайте атрибуты точно в том же порядке, что и в конструкторе bean. Попытка передать атрибуты в другом порядке вызовет исключения.
  4. Убедитесь, что запрос является допустимым запросом JPA, то есть он не является родным запросом. @Query("SELECT ...") или @Query(value = "SELECT ...") или @Query(value = "SELECT ...", nativeQuery = false), тогда как @Query(value = "SELECT ...", nativeQuery = true) не будет работать. Это связано с тем, что исходные запросы передаются без изменений поставщику JPA и выполняются в соответствии с базовыми СУБД как таковыми. Поскольку new и com.path.to.MyBean не являются действительными ключевыми словами SQL, RDBMS затем генерирует исключение.

Решение для собственных запросов

Как отмечено выше, синтаксис new ... является JPA-поддерживаемым механизмом и работает со всеми поставщиками JPA. Однако, если сам запрос не является запросом JPA, то есть является нативным запросом, синтаксис new ... не будет работать, поскольку запрос передается непосредственно в базовую RDBMS, которая не понимает ключевое слово new поскольку он не является частью стандарта SQL.

В подобных ситуациях классы bean-классов должны быть заменены интерфейсами Spring Data Projection .

Шаг 1: Объявить интерфейс проекции

package com.path.to.interface;

public interface SurveyAnswerStatistics {
  String getAnswer();

  int getCnt();
}

Шаг 2: Возвратить проецируемые свойства из запроса

@Query(nativeQuery = true,
       value = "SELECT " +
       "    v.answer AS answer, COUNT(v) AS cnt " +
       "FROM " +
       "    Survey v " +
       "GROUP BY " +
       "    v.answer")
List<SurveyAnswerStatistics> findSurveyCount();

Использовать SQL AS, чтобы отображать поля результатов в свойства проецирования для однозначного отображения.

90
ответ дан manish 16 August 2018 в 03:56
поделиться
  • 1
    Он не работает, ошибка обжига: Caused by: java.lang.IllegalArgumentException: org.hibernate.hql.internal.ast.QuerySyntaxException: Unable to locate class [SurveyAnswerReport] [select new SurveyAnswerReport(v.answer,count(v.id)) from com.furniturepool.domain.Survey v group by v.answer] at org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1750) at org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1677) at org.hibernate.jpa.spi.AbstractEnti.......... – Pranav C Balan 31 March 2016 в 09:45
  • 2
    Что это SurveyAnswerReport в вашем выходе. Я предполагаю, что вы заменили SurveyAnswerStatistics на свой собственный класс SurveyAnswerReport. Необходимо указать полное имя класса. – Bunti 31 March 2016 в 09:49
  • 3
    Класс bean должен быть полностью квалифицированным, то есть включать полное имя пакета. Что-то вроде com.domain.dto.SurveyAnswerReport. – manish 31 March 2016 в 09:50
  • 4
    @manish: Спасибо, человек сейчас работает! – Pranav C Balan 31 March 2016 в 10:46
  • 5
    Я получил 'java.lang.IllegalArgumentException: PersistentEntity не должно быть null! `, Когда я пытаюсь вернуть пользовательский тип из моего JpaRepository? Есть ли какая-то конфигурация, которую я пропустил? – marioosh 16 October 2017 в 09:12

Мне не нравятся имена типов java в строках запроса и обрабатывают его с помощью конкретного конструктора. Spring JPA неявно вызывает конструктор с результатом запроса в параметре HashMap:

@Getter
public class SurveyAnswerStatistics {
  public static final String PROP_ANSWER = "answer";
  public static final String PROP_CNT = "cnt";

  private String answer;
  private Long   cnt;

  public SurveyAnswerStatistics(HashMap<String, Object> values) {
    this.answer = (String) values.get(PROP_ANSWER);
    this.count  = (Long) values.get(PROP_CNT);
  }
}

@Query("SELECT v.answer as "+PROP_ANSWER+", count(v) as "+PROP_CNT+" FROM  Survey v GROUP BY v.answer")
List<SurveyAnswerStatistics> findSurveyCount();
1
ответ дан dwe 16 August 2018 в 03:56
поделиться

Этот список возврата SQL-запроса & lt; Object []> would.

Вы можете сделать это следующим образом:

 @RestController
 @RequestMapping("/survey")
 public class SurveyController {

   @Autowired
   private SurveyRepository surveyRepository;

     @RequestMapping(value = "/find", method =  RequestMethod.GET)
     public Map<Long,String> findSurvey(){
       List<Object[]> result = surveyRepository.findSurveyCount();
       Map<Long,String> map = null;
       if(result != null && !result.isEmpty()){
          map = new HashMap<Long,String>();
          for (Object[] object : result) {
            map.put(((Long)object[0]),object[1]);
          }
       }
     return map;
     }
 }
11
ответ дан ozgur 16 August 2018 в 03:56
поделиться

Я знаю, что это старый вопрос, на который уже был дан ответ, но вот еще один подход:

@Query("select new map(count(v) as cnt, v.answer) from Survey v group by v.answer")
public List<?> findSurveyCount();
6
ответ дан rena 16 August 2018 в 03:56
поделиться

определяют пользовательский класс pojo, скажем sureveyQueryAnalytics, и сохраняют возвращаемое значение запроса в вашем пользовательском классе pojo

@Query(value = "select new com.xxx.xxx.class.SureveyQueryAnalytics(s.answer, count(sv)) from Survey s group by s.answer")
List<SureveyQueryAnalytics> calculateSurveyCount();
2
ответ дан TanvirChowdhury 16 August 2018 в 03:56
поделиться
Другие вопросы по тегам:

Похожие вопросы: