Reputation: 1
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.
Upvotes: 0
Views: 1099
Reputation: 1
Posting as an answer not an update in order to help anyone who has the same issue.
private getRules() {
this.ruleService.getRuleList().subscribe(
res => {
this.rules = res.map(x => Object.assign(new Rule(), x));
My table is now displaying all values correctly. I think the issue was stemming from the getRules() method not properly converting the data from ruleService.getRuleList() into Rule objects. I found a similar question with a great answer that had lots of useful information, linked here.
Thank you to everyone who took the time to post suggestions and guidance!
Upvotes: 0
Reputation: 69
There's no need to manually convert your Java Object to Json. Spring Rest controllers do that by default. You can also specify it in your RestController like:
@RequestMapping(value = "/rules", method = RequestMethod.GET, produces = {MediaType.APPLICATION_JSON_VALUE})
Then in your Angular service it should automatically convert the json to your typescript object:
@Injectable({
providedIn: 'root'
})
export class RuleService {
private baseUrl = "http://localhost:4200/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 BadInput(error));
}
if (error.status === 404) {
return throwError(new NotFoundError());
}
return throwError(new AppError(error));
}
}
Just make sure that your typescript model has getters and setters (not 100% it is needed but try it out) and that the fields in the json match with your model's.
export class Rule {
constructor(private _messageCode?: string,
private _messageTypeCode?: string,
private _busRuleCode?: string,
private _externalMessageText?: string,
private _internalMessageText?: string) {
}
get messageCode(): string {
return this._messageCode;
}
set messageCode(value: string) {
this._messageCode= value;
}
.......
}
Last but not least. Try to change your getRules()
method in rule-list.component.ts
like:
private getRules() {
this.ruleService.getRuleList().pipe(
map(actions =>
actions.map(action => { return action as Rule;} )
)).subscribe(rules => this.rules = rules);
}
Upvotes: 1