0

I am using spring data rest, I have following entities exposed via spring data rest

DonationRequest

@Data
@Entity
@Table(name="donation_request",schema="public")
public class DonationRequest {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name="donation_request_id")
    Integer donationRequestId;

    @Column(name="expiry_datetime")
    Date expiryDatetime;

    @Column(name="blood_group")
    String bloodGroup;

    @Column(name="no_of_bottles")
    String noOfBottles;

    @OneToOne
    @JoinColumn(name="hospital_id")
    Hospital hospital;

    @OneToOne
    @JoinColumn(name="user_data_id")
    UserData requester;

    @Column(name="active")
    Boolean active;

}

Hospital

@Data
@Entity
@Table(name="hospital",schema="public")
public class Hospital {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name="hospital_id")
    Integer hospitalId;

    @Column(name="name")
    String name;

    @Column(name="address")
    String address;

    @Column(name="loc",columnDefinition = "geometry")
    Point loc;

}

Now I have an android client which has the same class definitions as stated above. Hospitals are cached at startup on android client. Now I want to create a donationRequest entity on server. I can do that easily by posting json of donationRequest object to /api/donationRequests. this json contains hospital object also. But the newly created donationRequest and hospital are not linked together.

Following type of json in postman does not create link:

{
    "bloodGroup":"AB+",
    "hospital":{
        "hospitalId":1
    }
}

I know that following json does create link:

{
    "bloodGroup":"AB+",
    "hospital":"/api/hospitals/1"
}

My question is how can I create link using first type of json as that is the natural way to serialize dontaionRequest object from android client? Also I want hospitals to be exposed via /api/hospitals, so removing that rest resource is not an option.

2 Answers 2

2

It can be achieved by using a custom HttpMessageConverter and defining a custom content-type which can be anything other than standard (I used application/mjson):

MHttpMessageConverter.java

public class MHttpMessageConverter implements HttpMessageConverter<Object>{
    @Override
    public boolean canRead(Class<?> aClass, MediaType mediaType) {
        if (mediaType.getType().equalsIgnoreCase("application")
                && mediaType.getSubtype().equalsIgnoreCase("mjson"))
            return true;
        else
            return false;
    }

    @Override
    public boolean canWrite(Class<?> aClass, MediaType mediaType) {
        return false;
    }

    @Override
    public List<MediaType> getSupportedMediaTypes() {
        return new ArrayList<>(Arrays.asList(MediaType.APPLICATION_JSON));
    }

    @Override
    public Object read(Class<?> aClass, HttpInputMessage httpInputMessage) throws IOException, HttpMessageNotReadableException {
        ObjectMapper mapper = new ObjectMapper();
        Object obj = mapper.readValue(httpInputMessage.getBody(),aClass);
        return obj;
    }

    @Override
    public void write(Object o, MediaType mediaType, HttpOutputMessage httpOutputMessage) throws IOException, HttpMessageNotWritableException {

    }
}

CustomRestConfiguration.java

@Configuration
public class CustomRestConfiguration extends RepositoryRestConfigurerAdapter {

    @Override
    public void configureHttpMessageConverters(List<HttpMessageConverter<?>> messageConverters) {
        messageConverters.add(new MHttpMessageConverter());
    }
}
Sign up to request clarification or add additional context in comments.

2 Comments

Pretty fun solution. A custom controller would not be easier?
With custom controller i would have to do it with all the entities seperately.
0

Spring Data REST is using HATEOAS. To refer to associated resources we have to use links to them:

Create a hospital first

POST /api/hospitals
{
    //...
}

response

{
    //...
    "_links": [
        "hostpital": "http://localhost/api/hospitals/1",
        //...
    ]
}

Then get 'hospital' (or 'self') link and add it to the 'donationRequests' payload

POST /api/donationRequests
{
    "bloodGroup":"AB+",
    "hospital": "http://localhost/api/hospitals/1"
}

Another approach - create first 'donationRequests' without hospital

POST /api/donationRequests
{
    //...
}

response

{
    //...
    "_links": [
        "hostpital": "http://localhost/api/donationRequests/1/hospital"
        //...
    ]
}

then PUT hospital to donationRequests/1/hospital using text link to hospital in your payload (pay attention to Content-Type: text/uri-list)

PUT http://localhost/api/donationRequests/1/hospital (Content-Type: text/uri-list)
http://localhost/api/hospitals/1

Info: Repository resources - The association resource

UPDATE

If it's necessary to deal without links to resources we have to make a custom rest controller.

2 Comments

Two things:- 1- hospitals are already created. I just want to reference. 2- I already told that I know that rest resource links can be used to create assocation links. I want to know if there is anyother solution?
check my answer.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.