We are attempting to have Swagger 2.0. Basically, it's great except it is ignoring the #JsonIdentityInfo and #JsonIdentityReference annotations.
public class Source {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#ManyToOne
#JsonIdentityReference(alwaysAsId=true)
#JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "name")
#JsonProperty("sourceDefinitionName")
private SourceDefinition sourceDefinition;
... getters and setters
}
Resulting in the Swagger schema output:
{
"id": 0,
"sourceDefinitionName": {
"configuration": {},
"driver": "string",
"id": "string",
"name": "string",
"sourceType": "QUERY",
"title": "string"
}
}
You can see that it indeed reads the #JsonProperty annotation renaming the "sourceDefinition" to "sourceDefinitionName" but the value should just be a string.
Does anyone have any insight into this sort of problem with this integration?
#ManyToOne(targetEntity = Source.class, optional = false)
#JoinColumn(name = "SOURCE_DEF_NAME", referencedColumnName = "name", nullable = false,
foreignKey = #ForeignKey(name = "FK_sourceDefName"))
private SourceDefinition sourceDefinition;
#Column(name = "SOURCE_DEF_NAME", insertable = false, updatable = false)
private String sourceDefinitionName;
Json identity is not working for me too. I have fond following workaround. see working example json-sample
Related
I have following relationship in my spring boot:
public class Clazz {
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Id
#Column(name = "id")
private Integer id;
#Column(name = "lesson_id")
#NotNull(message = "{lesson.is_required}")
private Integer lessonId;
#Column(name = "level_id")
#NotNull(message = "{level.is_required}")
private Integer levelId;
#Column(name = "name")
#NotEmpty(message = "{name.is_required}")
private String name;
#OneToOne
#JoinColumn(name = "lesson_id", referencedColumnName = "id", insertable = false, updatable = false)
private Lesson lesson;
#OneToOne
#JoinColumn(name = "level_id", referencedColumnName = "id", insertable = false, updatable = false)
private Level level;
}
Now my Lesson entity has Level entity:
public class Lesson {
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#Column(name = "name")
#NotEmpty(message = "{name.is_required}")
private String name;
#Column(name = "description")
private String description = "";
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
#JoinColumn(name = "lesson_id")
Collection<Level> levels = new ArrayList<>();
}
And finally my Level class:
public class Level {
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Id
#Column(name = "id", insertable = false, updatable = false)
private Integer id;
#Column(name = "lesson_id")
private Integer lessonId;
#Column(name = "name")
private String name;
#Column(name = "step")
private Integer step;
#Column(name = "description")
private String description="";
}
With this relationship defined, when I fetch data, getting some extra info in my results:
[
{
"id": 2,
"lessonId": 1,
"levelId": 1,
"name": "English Class March",
"branch": {
"id": 1,
"name": "3 mikr branch",
"email": "",
"phone": "",
"address": "3 mikr, foo, bar"
},
"lesson": {
"id": 1,
"name": "math",
"description": "math lesson",
"levels": [
{
"id": 1,
"lessonId": 1,
"name": "First level",
"step": 1,
"description": "1st level descr"
}
]
},
"level": {
"id": 1,
"lessonId": 1,
"name": "First level",
"step": 1,
"description": "1st level descr"
}
}
]
How can I tell JPA not to fetch sub-entities, ideally I do not need levels in lesson field of result.
Use #JsonIgnore. It can be used at setter,getter or field.
Please refer the code below.
public class Lesson {
#Id #Column(name = "id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#Column(name = "name")
#NotEmpty(message = "{name.is_required}")
private String name;
#Column(name = "description")
private String description = "";
#JsonIgnore // Add this to ignore the property in json output
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
#JoinColumn(name = "lesson_id")
Collection<Level> levels = new ArrayList<>();
}
Good night everyone,
I want to model a database that has the following entities and their perspective relationships:
But everytime I run the Java project to create the model at database, what I create is something like this:
There is another way to map this relationship? I'm mapping like that:
Article entity:
#Entity
public class Article {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(nullable = false)
private Boolean featured;
#Column(nullable = false)
private String title;
#Column(nullable = false)
private String url;
#Column(name = "image_url", nullable = false)
private String imageUrl;
#Column(name = "news_site", nullable = false)
private String newsSite;
#Column(nullable = false)
private String summary;
#Column(name = "published_at", nullable = false)
private String publishedAt;
#OneToMany
#JoinColumn(name = "launches_id")
private List<Launches> launches;
#OneToMany
#JoinColumn(name = "events_id")
private List<Events> events;
}
Launches entity
#Entity
public class Launches {
#Id
private String id;
private String provider;
}
Events entity:
#Entity
public class Events {
#Id
private Long id;
private String provider;
}
And I want to map this JSON, with this same launcher and events appearing in other articles:
{
"id": 4278,
"title": "GAO warns of more JWST delays",
"url": "https://spacenews.com/gao-warns-of-more-jwst-delays/",
"imageUrl": "https://spacenews.com/wp-content/uploads/2019/08/jwst-assembled.jpg",
"newsSite": "SpaceNews",
"summary": "",
"publishedAt": "2020-01-28T23:25:02.000Z",
"updatedAt": "2021-05-18T13:46:00.284Z",
"featured": false,
"launches": [
{
"id": "d0fa4bb2-80ea-4808-af08-7785dde53bf6",
"provider": "Launch Library 2"
}
],
"events": []
},
{
"id": 4304,
"title": "Government watchdog warns of another JWST launch delay",
"url": "https://spaceflightnow.com/2020/01/30/government-watchdog-warns-of-another-jwst-launch-delay/",
"imageUrl": "https://mk0spaceflightnoa02a.kinstacdn.com/wp-content/uploads/2020/01/48936479373_2d8a120c8e_k.jpg",
"newsSite": "Spaceflight Now",
"summary": "",
"publishedAt": "2020-01-30T04:08:00.000Z",
"updatedAt": "2021-05-18T13:46:01.640Z",
"featured": false,
"launches": [
{
"id": "d0fa4bb2-80ea-4808-af08-7785dde53bf6",
"provider": "Launch Library 2"
}
],
"events": []
}
According to your diagram, it should be:
#ManyToOne
#JoinColumn(name = "launches_id")
private Launches launches;
#ManyToOne
#JoinColumn(name = "events_id")
private Events events;
...and not #OneToMany ;) (Can there be an "Article" (with id=x) having launchers_id=y AND launchers_id=z? No, vice versa!:)
...for the #OneToMany, you should find the join columns "on the other side" (of relationship(s)).
According to your JSON, it is OneToMany. But then, we have to draw/expect:
#Entity
class Article {
//... id, columns, blah
#OneToMany
#JoinColumn(name = "article_id") // Launches "owns the relationship"/column
private List<Launches> launches;
#OneToMany
#JoinColumn(name = "article_id") // Events...!
private List<Events> events;
}
Generally, (when you expose your db model via json,) ensure:
no "circles" (in bi-directional associations). (#JsonManagedReference, #JsonBackReference, #JsonIgnoreProperties, ... )
not to expose data, that you don't want to expose. (#JsonIgnoreProperties, ...)
Regarding Hibernate-ManyToOne, please refer to https://vladmihalcea.com/the-best-way-to-map-a-onetomany-association-with-jpa-and-hibernate/
Regarding spring-data-jpa, best to:
gs-data-jpa
gs-data-rest
spring-boot-ref, data-jpa
reference-doc, data-jpa
reference-doc, data-rest
I have a rest api exposed via #RepositoryRestResource from spring-data-rest-api. When I try to give the json payload from Postman to create a User linked to an Organization, it complains that Column 'organizationId' cannot be null, when I clearly provided it in the json.
{
"firstName": "Test",
"lastName": "User",
"email": "user#example.com",
"phoneNumber": "+12019582790",
"organizationId": "22bf93a5-e620-4aaf-8333-ad67391fb235",
"password": "example123",
"role": "admin",
}
Each user belongs to an organization, so it's a many to one relationship. I want Java to map the Organization that the User belongs to into the User as an Organization object.
User.java:
#Entity
#Table(name="user")
public class User {
#ManyToOne(targetEntity = Organization.class, fetch = FetchType.EAGER)
#JoinColumn(name = "organizationId", nullable = false)
private Organization organization;
}
Organization.java:
#Entity
#Table(name = "organization")
public class Organization {
#Id
#GeneratedValue(generator = "id-generator")
#Type(type = "uuid-char")
#Column(name="organizationId")
private UUID organizationId;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "organization")
private Set<User> users;
}
Any help is greatly appreciated.
This is the appoach I ended up going with. Still would like to know why the #ManyToOne annotation isn't saving the organizationId as a foreign key in the User table by itself.
User.java:
#Type(type = "uuid-char")
#Column
private UUID organizationId;
#ManyToOne
#JoinColumn(name = "organizationId", insertable = false, updatable = false)
private Organization organization;
This is my entity class , which I am using to save the details of customer along with the purchase detail and product purchased and payment module , Its finely saving in DB but while retrieving getting result as null .
#Entity
#Table(name = "productpurchasedata")
public class Test {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int customerid;
#ManyToOne(cascade = { CascadeType.ALL })
#JoinColumn(name = "customerid", insertable = false, updatable = false)
private CustomerProductSave customerProductSave;
#ManyToOne(cascade = { CascadeType.ALL })
#JoinColumn(name = "customerid", insertable = false, updatable = false)
private PurchaseDetails purchasedetails;
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
#JoinColumn(name = "customerid")
private List<ProductPurchased> productpurchased;
#ManyToOne(cascade = { CascadeType.ALL })
#JoinColumn(name = "customerid", insertable = false, updatable = false)
private PaymentHistory paymenthistory;
Here I am able to save the data which result in something like this :-
{
"customerid": 1,
"customerProductSave": {
"customerids": 2,
"name": "nitesh",
"mailid": "niteshbhushan95#gmail.com",
"address": "hyd",
"city": "telanagana",
"state": "telanagana",
"postalcode": "847226",
"mobileno": 6300769631
},
"purchasedetails": {
"purchasedate": "22-07-2021",
"modeofpayment": "paytm",
"emiapplicable": false,
"totalamount": 21000,
"purchaseId": 4
},
"productpurchased": [
{
"purchaseid": 5,
"purchaseamount": 2000,
"purchasedproductid": 1,
"productquantity": 0
},
{
"purchaseid": 6,
"purchaseamount": 2000,
"purchasedproductid": 1,
"productquantity": 0
}
],
"paymenthistory": {
"transactionid": 3,
"paymentstatus": "paid"
}
}
Now when I am trying to retrieve the data by customerid it is not accepting , it giving message as null , I am not pretty much may be some mistake in mapping
try using fetch = FetchType.EAGER instead of fetch = FetchType.LAZY at all mappings
purchase detail and product purchased and payment module
I'm using Spring Boot 2.2, Spring Data REST, Spring HATEOAS.
I'm facing a strange problem. I've a RestController accepting this object:
#Data
public class DocumentJSON {
#Valid
private Document document;
private List<DocumentRow> rows = new ArrayList<>();
private List<DocumentVat> vats = new ArrayList<>();
private Set<DocumentPayment> payments = new HashSet<>();
private boolean updateContactDetail = false;
}
and DocumentPayment is:
#Data
#EqualsAndHashCode(callSuper = true, onlyExplicitlyIncluded = true)
#NoArgsConstructor
#AllArgsConstructor
#Builder
#ToString(callSuper = true)
public class DocumentPayment extends AbstractEntity {
#ToString.Exclude
#JsonDeserialize(using = DocumentUriDeserializer.class)
#NotNull
#OnDelete(action = OnDeleteAction.CASCADE)
#ManyToOne(fetch = FetchType.LAZY, optional = false)
private Document document;
#NotNull
#Column(nullable = false, columnDefinition = "DATE")
private Instant date;
//Optional contact (the receipt has not a contact)
#ToString.Exclude
#ManyToOne(fetch = FetchType.LAZY)
private Contact contact;
#NotBlank
#Column(nullable = false)
private String description;
#ToString.Exclude
#JsonDeserialize(using = FinancialAccountUriDeserializer.class)
#NotNull(message = "{documentpayment.financialaccount.missing}")
#ManyToOne(fetch = FetchType.LAZY, optional = false)
private FinancialAccount financialAccount;
#Enumerated(EnumType.STRING)
#NotNull
#Column(nullable = false, length = 30)
private PaymentType paymentType;
//The amount, negative for payment to suppliers
#NotNull
#ColumnDefault("0.00")
#Column(nullable = false, scale = 2, columnDefinition = "DECIMAL(12,2)")
private BigDecimal amount = BigDecimal.ZERO;
//The amount paid
#NotNull
#ColumnDefault("0.00")
#Column(nullable = false, columnDefinition = "DECIMAL(12,2)")
private BigDecimal paid = BigDecimal.ZERO;
#JsonProperty(access = JsonProperty.Access.READ_ONLY)
#Generated(value = GenerationTime.ALWAYS)
#Column(columnDefinition = "DECIMAL(12,2) AS (amount-paid) VIRTUAL NOT NULL")
private BigDecimal due;
#ToString.Exclude
#JsonDeserialize(using = StoreUriDeserializer.class)
//#NotNull(message = "{documentpayment.store.missing}")
#ManyToOne(fetch = FetchType.LAZY, optional = false)
#JoinColumn(name = "store_id", updatable = false)
private Store store;
}
The client is sending a Json like this:
{
"document": {
"date": "2019-10-18T00:00:00.000Z",
"type": "SALES_RECEIPT",
"store": "http://95.255.117.252:8082/api/v1/stores/1",
"rounding": 0,
"amount": 19.23,
"taxAmount": 0.77,
"totalAmount": 20
},
"rows": [
{
"index": 1,
"productType": "FRAME",
"qty": 1,
"rowGroup": null,
"unitPrice": 9.615,
"percentageDiscount": 0,
"purchaseUnitPrice": null,
"amount": 9.615,
"description": "Prodotto1",
"taxRate": "http://95.255.117.252:8082/api/v1/taxRates/2",
"note": false
},
{
"index": 1,
"productType": "OPHTHALMIC_LENS",
"qty": 1,
"rowGroup": null,
"unitPrice": 9.615,
"percentageDiscount": 0,
"purchaseUnitPrice": null,
"amount": 9.615,
"description": "Lente",
"taxRate": "http://95.255.117.252:8082/api/v1/taxRates/2",
"note": false
}
],
"payments": [
{
"date": "2019-10-18T00:00:00.000Z",
"financialAccount": "http://95.255.117.252:8082/api/v1/financialAccounts/1",
"paymentType": "CASH",
"amount": "10"
},
{
"date": "2019-10-18T00:00:00.000Z",
"financialAccount": "http://95.255.117.252:8082/api/v1/financialAccounts/3",
"paymentType": "CREDIT_CARD",
"amount": "10"
}
],
"updateContactDetail": false
}
but when I debug in the first line of the REST controller I see only 1 payment.
Changing the property payments in DocumentJSON from Set<DocumentPayment> to List<DocumentPayment>, I get 2 payments as expected with the same JSON.
Am I missing something or Spring/Jackson are not able to deserialize in the right way a Set<>?