Класс Scala неправильно десериализован Angular HttpClient - PullRequest
2 голосов
/ 13 апреля 2019

У меня есть следующие trait и classes в Scala:

sealed trait Algorithm {
  val name: String
  val formula: String
  val parameters: Seq[AlgorithmParameter[Any]]

  def enhanceAlgorithm[T](algorithm: T): Unit
}

case class LinearRegressionAlgorithm(override val name: String, override val formula: String) extends Algorithm {}
case class GeneralizedLinearRegressionAlgorithm(override val name: String, override val formula: String) extends Algorithm {}


sealed abstract class AlgorithmParameter[+T](val name: String, val value: T, val selectOptions: Seq[T]) extends EnumEntry

object AlgorithmParameter extends Enum[AlgorithmParameter[AnyVal]] with CirceEnum[AlgorithmParameter[AnyVal]] {

  case object MaxIter extends AlgorithmParameter[Int]("maxIter", 100, Seq())

}

Я создал в TypeScript соответствующие классы, которые выглядят так:

export abstract class Algorithm {

  readonly name: string;
  readonly formula: string;
  readonly parameters: AlgorithmParameter<any>[];

  protected constructor(name: string, formula: string, parameters: AlgorithmParameter<any>[]) {
    this.name = name;
    this.formula = formula;
    this.parameters = parameters;
  }
}

export class LinearRegressionAlgorithm extends Algorithm {}
export class GeneralizedLinearRegressionAlgorithm extends Algorithm {}

export class AlgorithmParameter<T> {

  readonly name: string;
  readonly value: T;
  readonly selectOptions: T[];

 constructor(name: string, value: T, selectOptions: T[]) {
   this.name = name;
   this.value = value;
   this.selectOptions = selectOptions;
 }
}

Я делаю REST-запрос к бэкэнду (часть Scala), который возвращает последовательность типа Seq[Algorithm], и я ожидаю, что ответ будет правильно переведен в классы Typescript, но это не так

Метод REST выглядит следующим образом:

recommend<T extends Algorithm>(body: RecommenderRequest): Observable<T[]> {

 return this.http.post<T[]>(environment.baseUrl + this.recommenderPath + this.algoRecommendationsPath, JSON.stringify(body))
  .catch((error: any) => Observable.throw(error.json().error || 'Server error'))
}

Ответ переводится в массив, выглядящий следующим образом:

enter image description here

Кажется, что TS algorithm-objects были созданы, но они инкапсулированы внутри другого объекта, и я не могу получить к ним доступ простым способом

Чтобы получить name первого алгоритма, вызов выглядит следующим образом: response[0].LinearRegressionAlgorithm.name, но я бы хотел, чтобы массив Http-response создавался таким образом, чтобы можно было просто написать response[0].name

1 Ответ

5 голосов
/ 14 апреля 2019

Angular не создает ваши объекты этих типов. Просто говорят, что это набор текста. Ваша программа Scala возвращает данные, как показано. Вам нужно будет выполнить операцию с картой для каждого из результатов, чтобы получить правильные объекты.

Пример ниже:

recommend<T extends Algorithm>(body: RecommenderRequest): Observable<T[]> {
  return this.http.post<T[]>(environment.baseUrl + this.recommenderPath + this.algoRecommendationsPath, JSON.stringify(body)).pipe(
    map(algorithms => algorithms.map(algorithm => this.toAlgorithm(algorithm)),
    catchError(error => Observable.throw(error.json().error || 'Server error'))
  );
}

private toAlgorithm(algorithm: { [type: string]: Partial<Algorithm> }): Algorithm {
  const type = Object.keys(algorithm)[0];
  const name = algorithm[type].name;
  const formula = algorithm[type].formula;
  const parameters = (algorithm[type].parameters || [])
    .map(parameter => this.toParameter(parameter));

  switch (type) {
    case 'LinearRegressionAlgorithm':
      return new LinearRegressionAlgorithm(name, formula, parameters);

    case 'GeneralizedLinearRegressionAlgorithm':
      return new GeneralizedLinearRegressionAlgorithm(name, formula, parameters);

    default:
      throw new Error('Unsupported algorithm');
  }
}

private toParameter(paramerter: Partial<AlgorithmParameter<any>>): AlgorithmParameter<any> {
  return new AlgorithmParameter<any>(parameter.name, parameter.value, parameter.selectedOptions);
}

Если вам не нужны фактические экземпляры этих алгоритмов и вам просто нужны значения в алгоритмах, вы можете изменить классы Algorithm на интерфейсы, и это намного проще:

recommend<T extends Algorithm>(body: RecommenderRequest): Observable<T[]> {
  return this.http.post<T[]>(environment.baseUrl + this.recommenderPath + this.algoRecommendationsPath, JSON.stringify(body)).pipe(
    map(algorithms => algorithms.map(algorithm => Object.values(algorithm)[0]),
    catchError(error => Observable.throw(error.json().error || 'Server error'))
  );
}

Делая так, вы потеряете любую информацию о типе алгоритма, так что вы захотите добавить другое свойство в свой интерфейс алгоритма для типа и установить его в процессе отображения выше. Просто зависит от ваших потребностей.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...