I'm trying to use Angular and Spring Boot to show a list of Rule objects. I am not using a JPA Repository to respond to the GET request, so I think I have to 'manually' convert my list of Rule objects on the Spring Boot side to a JSON so that httpClient.get<Rule[]>() can convert it to a list of Rule objects on the Angular side. However, this is currently not working, and my rule objects are not showing up on my webapp.
I'm not using a repository because I'm querying the database on the Spring Boot side, and doing some business logic to only display rules that fall under a certain criteria, and adding some information about the rules that is not in the database.
How do I correctly convert the list of rules to a JSON? Is this even the right approach?
Thank you!
Rule.java:
@Entity
@Table(name = "MSG_DOM")
public class Rule implements Serializable{
private static final long serialVersionUID = 1L;
private String fireType;
private boolean multipleDrivers;
@Id
@Column(name = "MSG_CD", unique = true, nullable = false)
private String messageCode;
@Column(name = "MSG_TYP_CD", unique = false, nullable = false)
private String messageTypeCode;
@Column(name = "BUS_RUL_CD", unique = false, nullable = false)
private String busRuleCode;
@Column(name = "MSG_EXTR_USER_TXT", unique = false, nullable = false)
private String externalMessageText;
@Column(name = "MSG_INTRL_USER_TXT", unique = false, nullable = false)
private String internalMessageText;
public Rule(){}
public String getMessageCode(){
return messageCode;
}
public void setMessageCode(String messageCode){
this.messageCode = messageCode;
}
...
RuleController.java:
@RestController
@RequestMapping("/api/v1")
public class RuleController {
//get all rules
@CrossOrigin(origins = "http://localhost:4200")
@RequestMapping(value = "/rules", method = RequestMethod.GET, produces = {MediaType.APPLICATION_JSON_VALUE})
@ResponseBody
public Rule[] getAllRules() {
RuleListService ruleListService = new RuleListService();
List<Rule> ruleList = ruleListService.listRules();
Rule[] rules = new Rule[ruleList.size()];
for (int i = 0; i < ruleList.size(); ++i) rules[i] = ruleList.get(i);
return rules;
}
}
RuleListService.java:
public class RuleListService {
ApplicationContext context = new AnnotationConfigApplicationContext(BeanConfig.class);
public List<Rule> listRules() {
RuleList lister = context.getBean(RuleList.class);
ArrayList<HashMap<String, Rule>> ruleMaps = lister.loadRuleMap();
ArrayList<Rule> ruleList = new ArrayList<Rule>();
for(HashMap<String, Rule> ruleMap: ruleMaps) {
ruleList.addAll(ruleMap.values());
}
return ruleList;
}
}
rule.ts:
export class Rule {
constructor(
private _serialVersionUID : number,
private _fireType: string,
private _multipleDrivers: boolean,
private _messageCode: string,
private _messageTypeCode: string,
private _busRuleCode: string,
private _externalMessageText: string,
private _internalMessageText: string,) {
}
getSerialVersionUID() : number {
return this._serialVersionUID;
}
setSerialVersionUID(value: number) {
this._serialVersionUID = value;
}
...
rule.service.ts:
@Injectable({
providedIn: 'root'
})
export class RuleService {
private baseUrl = "http://localhost:8080/api/v1/rules"
constructor(private httpClient: HttpClient) {}
getRuleList(): Observable<Rule[]> {
return this.httpClient.get<Rule[]>(`${this.baseUrl}`).pipe(
catchError(this.handleError)
);
}
private handleError = (error: Response) => {
if (error.status === 400) {
return throwError(() => new Error("Bad Input"));
}
if (error.status === 404) {
return throwError(() => new Error("Not Found"));
}
return throwError(() => new Error("App Error"));
}
}
rule-list.component.ts:
export class RuleListComponent implements OnInit {
rules: Rule[];
ruleTest: Rule;
constructor(private ruleService: RuleService) { }
ngOnInit(): void {
this.getRules();
}
private getRules() {
this.ruleService.getRuleList().pipe(
map((actions: Rule[]) =>
actions.map(action => { return action as Rule;} )
)).subscribe(rules => this.rules = rules);
}
}
rule-list.component.html:
<h2> Rule List </h2>
<table class = "table table-striped">
<thead>
<tr>
<th> MSG_CD </th>
<th> MSG_TYP_CD </th>
<th> BUS_RUL_CD </th>
<th> MSG_EXTR_USER_TXT </th>
<th> MSG_INTRL_USER_TXT </th>
<th> Fire Type </th>
<th> Multiple Drivers </th>
</tr>
</thead>
<tbody>
<tr *ngFor = "let rule of rules" >
<td> {{rule.getMessageCode()}} </td>
<td> {{rule.getMessageTypeCode()}} </td>
<td> {{rule.getBusRuleCode()}} </td>
<td> {{rule.getExternalMessageText()}}</td>
<td> {{rule.getInternalMessageText()}} </td>
<td> {{rule.getFireType()}} </td>
<td> {{rule.getMultipleDrivers()}} </td>
</tr>
</tbody>
</table>
UPDATE: I'm still not seeing the data in the table, and have gotten this error from the dev console on my browser:
ERROR TypeError: rule_r1.getMessageCode is not a function
at RuleListComponent_tr_20_Template (rule-list.component.html:16:18)
I tried changing the variables to public in the Rule.ts constructor, and accessing the variables directly instead of calling get() methods like so, {{rule._messageCode}}, for all table fields, and while it (obviously) got rid of the error, I still did not see data in the table.
The table has been populated with rows indicating there is actually a Rule[] being sent and received correctly, but there is no data in any row.
I've also updated all included code, since many changes have been made.
return gson.toJson(ruleListService.listRules());justreturn ruleListService.listRules()ditch the GSON stuff. You also have to make sure that your fields match (in the DTO on the java side and the DTO on the JS side, currently they don't so no binding/conversion on the JS side will occur).getMessageCode()