Swagger resolver error - could not resolve pointer [duplicate] - java

This question already has an answer here:
Could not resolve pointer: /definitions/Error-ModelName
(1 answer)
Closed 1 year ago.
I have a Spring controller method as follows.
#PutMapping("/update")
public ResponseEntity<String> updateMethod(#RequestBody() ListDto listDto) {
...
}
The input parameter should be an instance of the ListDto class. The ListDto class is as follows.
#Data
#ApiModel(description = "update list dto")
public class ListDto extends ArrayList<ObjectDto> {
}
The ObjectDto class is as follows.
#Data
#ApiModel(description = "update object dto")
public class ObjectDto {
#ApiModelProperty(example = "1")
private String id;
#ApiModelProperty(example = "new message")
private String message;
}
The issue is, when trying to use the method in Swagger, I get the below error - seems like the swagger definition for the ObjectDto class does not get created at runtime.
Is there a way to force the definition to get created and make this error disappear?

Try and reinstall your schema.
To do so You can Simply reinstall swagger!

Related

ObjectMapper adds extra Field to the JSON String

I have the following problem.
Here is my Accident class and the CommonDomainEntity class:
#NoArgsConstructor
#AllArgsConstructor
#Data
public class Accident extends CommonDomainObject {
private String status;
private Date accidentDate;
private String name;
}
#Data
public abstract class CommonDomainObject {
public Long id;
public boolean isNew() {
return null == getId();
}
}
In my test class I am calling the following:
String exp = objMapper.writeValueAsString(accidents);
System.out.println(exp);
ResponseEntity<String> res = restTemplate.getForEntity("/accidents", String.class);
assertEquals(HttpStatus.OK, res.getStatusCode());
JSONAssert.assertEquals(exp, res.getBody(), false);
It throws the following error:
java.lang.AssertionError: [id=2]
Expected: new
but none found
; [id=3]
Expected: new
but none found
I already tried to out print the object exp to see whats in it, as well as I tried to print whats inaccidents`.
As you see in the console logs, for some reason in the exp object there is a new=false field, and I can`t figure out where this is from.
This right here is what is in my accidents List
Accident(status=pending, accidentDate=null, name=Name),
Accident(status=closed, accidentDate=null, name=Name)]
And this is my exp object as JSON
[{"id":2,"status":"pending","accidentDate":null,"name":"Name","new":false},
{"id":3,"status":"closed","accidentDate":null,"name":"Name","new":false}]
Your CommonDomainObject.isNew() method in the abstract class is evaluated as a JSON field by ObjectMapper. You must exclude it using jackson anotations.
public abstract class CommonDomainObject {
...
#JsonIgnore
public boolean isNew() {
return null == getId();
}
}
See:
Want to hide some fields of an object that are being mapped to JSON by Jackson
https://github.com/FasterXML/jackson-annotations/wiki/Jackson-Annotations
https://github.com/FasterXML/jackson-annotations
Your MCVE would be:
Call objMapper.writeValueAsString()
Check why the resulting JSON string representation contains the new field
All the other code is reduntant for the reproduction of your issue :)

What is the best way to get response without HATEOAS?

I tried get entity by Data JPA & Data Rest without HATEOAS.
The condition is that I use the HATEOAS form, and sometimes I need a pure Json response.
So I'm creating JSON by creating the controller path separately from the repository's endpoint and creating the DTO class separately.
this is my code :
#RepositoryRestController
public class MetricController {
#Autowired
private MetricRepository metricRepository;
#RequestMapping(method = RequestMethod.GET, value = "/metrics/in/{id}")
public #ResponseBody
MetricDTO getMetric(#PathVariable Long id) {
return MetricDTO.fromEntity(metricRepository.getOne(id));
}
}
#RepositoryRestResource
public interface MetricRepository extends JpaRepository<Metric, Long> { }
#Setter
#Getter
#NoArgsConstructor
#AllArgsConstructor
public class MetricDTO {
private SourceType sourceType;
private String metricTypeField;
private String metricType;
private String instanceType;
private String instanceTypeField;
private List<String> metricIdFields;
private List<String> valueFields;
private Map<String, String> virtualFieldValueEx;
public static MetricDTO fromEntity(Metric metric) {
return new MetricDTO(
metric.getSourceType(),
metric.getMetricTypeField(),
metric.getMetricType(),
metric.getInstanceType(),
metric.getInstanceTypeField(),
metric.getMetricIdFields(),
metric.getValueFields(),
metric.getVirtualFieldValueEx()
);
}
}
It's the way I do, but I expect there will be better options and patterns.
The question is, I wonder if this is the best way.
HATEOAS (Hypermedia as the Engine of Application State) is a constraint of the REST application architecture.
It basically tells that anyone who is a consumer of your REST endpoints can navigate between them with the help of the link.
let take your example
**HTTP Method** **Relation (rel)** **Link**
GET Up /metrics/in
GET Self /metrics/in/{id}
GET SourceType /sourceType/{id}
GET metricIdFields /url for each in JSON aarray
Delete Delete /employe/{employeId}
Use org.springframework.hateoas.Links class to create such link in your DTOs.
in you DTO add
public class MetricDTO {
private Links links;
//Getters and setters
//inside your setters add SLEF , GET , create Delete for current resource
}
https://www.baeldung.com/spring-hateoas-tutorial

Spring JPA data repository not acting like it should

I am new to Spring and I am trying to create an Object and add it to my database and then get the value from it. As far as I understand I should not add any extra lines and findAll should return me a proper looking String as a result.
But the result I get looks like this:
[model.Orders#4a163575, model.Orders#7ecec90d]
What I also understood is that I should not add get/set methods to Spring as they should be automatically generated, but when I try to cast the model.Orders#4a163575 into an Object and do the get method It tells me that there is no get method.
So here is my Object:
#Data
#Entity
public class Orders {
public Orders(String orderName) {
this.orderName = orderName;
}
public Orders() {
}
#Id
#GeneratedValue
private Long id;
private String orderName;
}
Then the findAll method:
#Repository
public class OrderDao {
public List<Orders> findAll(){
return em.createQuery("select p from Orders p", Orders.class).getResultList();
}
}
And where I launch it all:
public static void main(String[] args) {
ConfigurableApplicationContext ctx =
new AnnotationConfigApplicationContext(DbConfig.class);
OrderDao dao = ctx.getBean(OrderDao.class);
dao.save(new Orders("order1"));
dao.save(new Orders("order2"));
System.out.println(dao.findAll());
}
From what I have I think that the #Data annotation is not working properly since there is no toString nor getters/setter.
I import the #Data annotation with this line : import lombok.Data;.
What am I doing wrong here.
You need to install lombok plugin for that it will be possible generating them
You can refer to this article how to install lombok in IntellijIdea:
Lombok annotations do not compile under Intellij idea
Please also add enable annotation processing
Well it seems I had forgotten to enable annotation processing.
Picture to show where and how I did it

Spring Boot JPA with Hibernate Spatial self-reference leading to cycle

I am currently writing a service where I can store a geospatial point with some data. I have a "dataPoint" class that looks like this:
#Entity
#Table(name = "datapoint")
public class DataPoint {
#Id
int dataPoint_id;
#Column(name = "body")
String body;
#Column(name = "location", columnDefinition = "Geometry")
PGgeometry location;
#Column(name = "deleted")
boolean deleted;
//Getters and Setters...
I am trying to use Spring Boot to simply add a point with some information to a PostGIS database via an API path. I have built a controller that looks like this:
#RestController
#RequestMapping(value = "/dataPoint")
public class DataPointController {
#Autowired
private DataPointService myPointService;
#RequestMapping(value = "/add/{body}/{latitude}/{longitude}/")
public DataPoint addDataPoint(#PathVariable String body, #PathVariable double latitude, #PathVariable double longitude){
DataPoint myPoint = new DataPoint();
myPoint.setBody(body);
PGgeometry geometry = new PGgeometry();
try {
geometry.setValue("POINT("+longitude +" " + latitude+")");
geometry.setType("POINT");
// Debugging Stuff
System.out.println("GEOMETRY VALUE LOOK: {{{{ " + geometry.getValue() + " " + geometry.getType());
} catch (SQLException e) {
e.printStackTrace();
}
myPoint.setLocation(geometry);
myPointService.saveDataPoint(myPoint);
return myPoint;
}
Which is in turn linked to a DataPointService which just acts as a middle man between the controller where saveDataPoint() looks like this:
public void saveDataPoint(DataPoint myPoint) {
dataPointRepository.save(myPoint);
}
and the DataPointRepository, which looks like this:
#Repository
public interface DataPointRepository extends JpaRepository<DataPoint, Integer> {
}
However, when I visit my add link, I get this error:
Failed to write HTTP message: org.springframework.http.converter.HttpMessageNotWritableException: Could not write content: Direct self-reference leading to cycle (through reference chain: com.testing.model.DataPoint["location"]->org.postgis.PGgeometry["geometry"]->org.postgis.Point["firstPoint"]); nested exception is com.fasterxml.jackson.databind.JsonMappingException: Direct self-reference leading to cycle (through reference chain: com.testing.model.DataPoint["location"]->org.postgis.PGgeometry["geometry"]->org.postgis.Point["firstPoint"])
I have seen the #JsonBackReference and its dual used in some examples, however, that has been used in situations where entities are being linked back and forth, which I do not see happening here, in fact, the error does not even seem to be cyclic, so what is happening here?
I ran into the same issue. It's cyclic because Point has a field firstPoint that reference to Point again.
I was able to resolve the problem by installing this postgis-geojson: https://jitpack.io/p/stephenbrough/postgis-geojson

How does SpringBoot deserialize JSON, and when does it do it?

I'm currently working on a SpringBoot API to interface with a MongoRepository, but I'm having trouble understanding how the JSON being passed becomes a Document for storage within Mongo. I currently have a simple API that stores a group of users:
#Document
#JsonInclude
public class Group {
#Id
#JsonView(Views.Public.class)
private String id;
#JsonView(Views.Public.class)
private String name;
#JsonView(Views.Public.class)
private Set<GroupMember> groupMembers = new HashSet<>();
}
There are also setter and getter methods for each of the fields, although I don't know how necessary those are either (see questions at the end).
Here is the straightforward component I'm using:
#Component
#Path("/groups")
#Api(value = "/groups", description = "Group REST")
public class Groups {
#Autowired
private GroupService groupService;
#GET
#Produces(MediaType.APPLICATION_JSON)
#ApiOperation(value = "Get all Groups", response = Group.class, responseContainer = "List")
#JsonView(Views.Public.class)
public List<Group> getAllGroups() {
return groupService.getAllGroups();
}
#POST
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
#ApiOperation(value = "Create a Group", response = Group.class)
#JsonView(Views.Detailed.class)
public Group submitGroup(Group group) {
return groupService.addGroup(group);
}
}
Finally, I have a Service class:
#Service
public class GroupServiceImpl implements GroupService {
#Autowired
private GroupRepository groupRepository;
#Override
public Group addGroup(Group group) {
group.setId(null);
return groupRepository.save(group);
}
#Override
public List<Group> getAllGroups() {
return groupRepository.findAll();
}
}
The GroupRespository is simply an interface which extends MongoRepository<Group,String>
Now, when I actually make a call to the POST method, with a body containing:
{
"name": "group001",
"groupMembers": []
}
I see that it properly inserts this group with a random Mongo UUID. However, if I try to insert GroupMember objects inside the list, I receive a null pointer exception. From this, I have two questions:
How does SpringBoot (Jackson?) know which fields to deserialize from the JSON being passed? I tested this after deleting the getter and setter methods, and it still works.
How does SpringBoot handle nested objects, such as the Set inside the class? I tested with List instead of Set, and it worked, but I have no idea why. My guess is that for each object that is both declared in my class and listed in my JSON object, SpringBoot is calling a constructor that it magically created behind the scenes, and one doesn't exist for the Set interface.
Suppose I'm adamant on using Set (the same user shouldn't show up twice anyway). What tools can I use to get SpringBoot to work as expected?
It seems to me that a lot of the things that happen in Spring are very behind-the-scenes, which makes it difficult for me to understand why things work when they do. Not knowing why things work makes it difficult to construct things from scratch, which makes it feel as though I'm hacking together a project rather than actually engineering one. So my last question is something like, is there a guide that explains the wiring behind the scenes?
Finally, this is my first time working with Spring... so please excuse me if my questions are entirely off the mark, but I would appreciate any answers nonetheless.

Categories