Scala class 未被 Angular HttpClient 正确反序列化
Scala class isn't deserialised correctly by Angular HttpClient
我在 Scala
中有以下 trait
和 classes
:
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;
}
}
我正在做的是向后端(Scala 部分)发出 REST 请求,其中 returns 类型为 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'))
}
响应被翻译成一个数组,如下所示:
好像已经创建了TS algorithm-objects
,但是它们被封装在另一个对象中,我无法轻松访问
为了得到第一个算法的name
,调用看起来如下:
response[0].LinearRegressionAlgorithm.name
,但我希望以这样的方式创建 Http-response 数组,以便可以简单地编写 response[0].name
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'))
);
}
以这种方式做事你会丢失任何关于算法类型的信息,所以你会想在你的算法接口上添加另一个 属性 类型并在上面的映射过程中设置它。就看你的需求了。
我在 Scala
中有以下 trait
和 classes
:
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;
}
}
我正在做的是向后端(Scala 部分)发出 REST 请求,其中 returns 类型为 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'))
}
响应被翻译成一个数组,如下所示:
好像已经创建了TS algorithm-objects
,但是它们被封装在另一个对象中,我无法轻松访问
为了得到第一个算法的name
,调用看起来如下:
response[0].LinearRegressionAlgorithm.name
,但我希望以这样的方式创建 Http-response 数组,以便可以简单地编写 response[0].name
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'))
);
}
以这种方式做事你会丢失任何关于算法类型的信息,所以你会想在你的算法接口上添加另一个 属性 类型并在上面的映射过程中设置它。就看你的需求了。