I carefully studied the discussion "JAXB Adding attributes..." and would like to move a little further.
For example, there is a following class:
#XmlRootElement(name = "company")
#XmlType(propOrder = {"id", "name", "address"})
public class Company {
private String id;
private String name;
private String address;
#XmlElement(name = "id")
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
#XmlElement(name = "name")
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#XmlElement(name = "address")
public String getAddress() {
return name;
}
public void setAddress(String address) {
this.address = address;
}
}
After marshaling an object we have:
<company>
<id>1</id>
<name>Abc</name>
<address>Mountain View, United States</address>
</company>
Is there an elegant solution, - for example using annotations #XmlPaths, #XmlPath, #XmlElements, #XmlElement, - to receive as a result:
<company>
<id>1</id>
<name lang="en">Abc</name>
<address lang="en">Mountain View, United States</address>
</company>
How about creating a custom String with the lang attribute and use that instead of string
for example :
public class LangString {
#XmlValue
protected String value;
#XmlAttribute(name = "lang")
#XmlJavaTypeAdapter(CollapsedStringAdapter.class)
#XmlSchemaType(name = "language")
protected String lang;
//GETTERS & SETTERS
}
Your code :
#XmlRootElement(name = "company")
#XmlType(propOrder = {"id", "name", "address"})
public class Company {
private String id;
private LangString name;
private LangString address;
#XmlElement(name = "id")
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
#XmlElement(name = "name")
public LangString getName() {
return name;
}
public void setName(LangString name) {
this.name = name;
}
#XmlElement(name = "address")
public LangString getAddress() {
return name;
}
public void setAddress(LangString address) {
this.address = address;
}
}
The code above was generated from an xsd schema for my application that had elements with the lang attribute thus the #XmlSchemaType.
Hope it helps
Related
I Have a rest controller that is not de-serializing the array type in json..
#PostMapping()
#ResponseBody
public ResponseEntity<Team> createteam(#RequestBody Team team) throws JsonProcessingException {
Team savedTeam = teamService.createTeam(team);
return new ResponseEntity<Team>(savedTeam, HttpStatus.CREATED);
}
below is my entity class.
#Entity
#JsonIdentityInfo(generator = IntSequenceGenerator.class)
public class Team {
#Id
#GeneratedValue
private Long id;
private String name;
#OneToMany(mappedBy = "team", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private List<Developer> developers;
public Team(String name, List<Developer> developer) {
super();
this.name = name;
this.developers = developer;
}
public Team() {
super();
}
public List<Developer> getDeveloper() {
return developers;
}
public void setDeveloper(List<Developer> developer) {
this.developers = developer;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
and my other entity..
package com.demo.springbootdemo.entity;
#Entity
#JsonIdentityInfo(generator = IntSequenceGenerator.class)
public class Developer {
#Id
#GeneratedValue
private Long id;
#ManyToOne
private Team team;
private Long phone;
private String name;
public Developer() {
super();
}
public Developer(Team team, Long phone, String name) {
super();
this.team = team;
this.phone = phone;
this.name = name;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Team getTeam() {
return team;
}
public void setTeam(Team team) {
this.team = team;
}
public Long getPhone() {
return phone;
}
public void setPhone(Long phone) {
this.phone = phone;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
below is my JSON payload, which returns null "developers" when i call the post method.i have tried changing the number of properties in json payload but, still i am not able to figure out why my json is not de-serilaized to List of developers..
{
"id": 1004,
"name": "claim",
"developers": [
{
"id" :1,
"phone": 9092123,
"name": "raina"
}
]
}
I am not sure what Deserializer are you using, but with the Jackson ObjectMapper I solved it changing the method names of the getter and setter for the developers properties: they should be called setDevelopers and getDevelopers. In your code they are called setDeveloper and getDeveloper, without the final S.
To avoid problem like these, I just add Lombok as a dependency and it takes care of creating setters and getters.
With Lombok your Team class would look like this:
// ... more imports here...
import lombok.Data;
#Data
#JsonIdentityInfo(generator = ObjectIdGenerators.IntSequenceGenerator.class)
public class Team {
#Id
#GeneratedValue
private Long id;
private String name;
#OneToMany(mappedBy = "team", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private List<Developer> developers;
}
You may need to add more Lombok annotations for generating constructor methods according to your needs.
I'm learning Spring Framework, i followed some tutorials of relationship 1-1, so i defined my models: One Library have one Address.
I send in my body request the library data and the id from the address, the spring create the record, but he can't do the relationship, returning address null and when i make a select in database, the address_id is not saving in the table library
This is what i tried:
My model Library:
#Entity
#Table(name = "Bibliotecas")
public class Library implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
private String name;
#OneToOne
#JoinColumn(name = "address_id", referencedColumnName = "id")
private Address address;
public Library() {
}
public long getId() {
return this.id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public Address getAddress() {
return this.address;
}
public void setAddress(Address address) {
this.address = address;
}
}
My model Address:
#Entity
public class Address {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
#Column(nullable = false)
private String location;
public long getId() {
return this.id;
}
public void setId(long id) {
this.id = id;
}
public String getLocation() {
return this.location;
}
public void setLocation(String location) {
this.location = location;
}
#OneToOne(mappedBy = "address", fetch = FetchType.LAZY, optional = false)
private Library library;
}
My repositories:
public interface LibraryRepository extends JpaRepository<Library, Long> {}
public interface AddressRepository extends JpaRepository<Address, Long> {}
My library resource:
#RestController
#RequestMapping(value = "/api")
public class LibraryResource {
#Autowired
LibraryRepository libraryRepository;
#GetMapping("/libraries")
public List<Library> listaBibliotecas() {
return libraryRepository.findAll();
}
#PostMapping("/library")
public Library salvaBiblioteca(#RequestBody Library library) {
return libraryRepository.save(library);
}
}
I do this request in Postman:
{
"name": "library test",
"address_id": 1
}
Obs: i have one address with id 1 in database, but i receive:
{
"id": 5,
"name": "Biblioteca test",
"address": null
}
Why i'm receiving null in my return? And why my register is not saving the address_id?
Please consider the following:
You switched the mapping between address & library
Better to user Hibernate annotations on public fields
Address -> Library getter & setter not implemented
Address entity missing the #table annotation
This must work for you:
Library:
#Entity
#Table(name = "library")
public class Library implements Serializable {
private static final long serialVersionUID = 1L;
private long id;
private String name;
private Address address;
public Library() {
}
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
public long getId() {
return this.id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
#OneToOne(mappedBy = "library", cascade = CascadeType.ALL, fetch = FetchType.LAZY, optional = false)
public Address getAddress() {
return this.address;
}
public void setAddress(Address address) {
this.address = address;
}
}
Address:
#Entity
#Table(name = "address")
public class Address {
private long id;
private String location;
private Library library;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
public long getId() {
return this.id;
}
public void setId(long id) {
this.id = id;
}
#Column(nullable = false)
public String getLocation() {
return this.location;
}
public void setLocation(String location) {
this.location = location;
}
#OneToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "id")
public Library getLibrary() {
return library;
}
public void setLibrary(Library library) {
this.library = library;
}
}
Better never expose your repositories to controller, you should instead reference a service that has access to repositoryDao.
Use same entity name as table name is better approach.
I am playing with Spring JPA, and not able to achieve below:
#Entity
#Table(name = "User")
public class User implements Serializable {
#Column
private String name;
#OneToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER, orphanRemoval = true)
private Address address;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
protected long id;
private final static long serialVersionUID = 1L;
}
#Entity
#Table(name = "Location")
public class Location implements Serializable {
#Column
private String address;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
protected long id;
private final static long serialVersionUID = 1L;
}
I have repositories for each domain model.
I want to get 'Address' by name such as 'findAddressByName()'. I have tried various different thing but always get User back. Can I get Address ? Is there a way to do ? Or that is how domain model specific works by default.
I have two tables: authors and books
Author:
#Entity
#Table (name="authors")
public class Author implements java.io.Serializable {
private Integer id;
private String name;
private String lastName;
/*book list*/
private Set<Book> books= new HashSet<Book>(0);
public Author() {
}
public Author(String name, String lastName) {
this.name = name;
this.lastName = lastName;
}
public Author(String name, String lastName, Set<Book> books) {
this.name = name;
this.lastName = lastName;
this.books = books;
}
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "AUTHOR_ID", unique = true, nullable = false)
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
#Column(name = "AUTHOR_NAME", unique = true, nullable = false, length = 10)
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#Column(name = "AUTHOR_LASTNAME", unique = true, nullable = false, length = 10)
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
#OneToMany(fetch = FetchType.LAZY, mappedBy = "author")
public Set<Book> getBooks() {
return books;
}
public void setBooks(Set<Book> books) {
this.books = books;
}
}
Book:
import javax.persistence.*;
#Entity
#Table(name = "books")
public class Book implements java.io.Serializable {
private Integer id;
private String name;
private Author author;
public Book() {
}
public Book(String name) {
this.name = name;
}
public Book(String name, Author author) {
this.name = name;
this.author = author;
}
#Id
#Column(name = "BOOK_ID")
#GeneratedValue(strategy = GenerationType.IDENTITY)
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
#Column(name = "BOOK_NAME")
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "AUTHOR_ID",nullable = false)
public Author getAuthor() {
return author;
}
public void setAuthor(Author author) {
this.author = author;
}
}
In my book's table I have field with id author. How can I get all books from one author? How Can I solve it?
Must I use HQL or other methods? I am beginner in this.
first you need to the mapping between two entities.
Author class
#OneToMany(mappedBy="author")
private Set<Book> books= new HashSet<Book>(0);
Book class
#ManyToOne
private Author author;
after that you can use a simple criteria query to retrieve the relevant records.
I wont help you with the code here but the logic..
The very first thing you need to do is build a relationship between Author and Books using the annotations #OneToMany or #ManyToOne depending on your structure.
Next use the Author Class Object to retrive the list of Books.
I have hibernate #OneToMany mapping I am getting the mentioned error. Does not understand the reason. As getters and setters are public
Below are the entities
#Entity
#Table(name="USER_DETAILS")
public class User implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
#Id
#Column(name="USER_ID")
#GeneratedValue(strategy=GenerationType.AUTO)
private int id;
#Column(name="USER_FIRSTNAME",nullable=false, length=50)
private String userFirstName;
#Column(name="USER_LASTNAME",nullable=false, length=50)
private String userLastName;
#Column(name="USER_MIDDLENAME",length = 30)
private String userMiddleName;
#Column(name="USER_AGE")
private int userAge;
#Column(name="USER_SEX")
private String userSex;
#OneToMany(cascade=CascadeType.ALL, mappedBy="userAddress", targetEntity=Address.class)
private Set<Address> address = new HashSet<Address>();
public String getUserFirstName() {
return userFirstName;
}
public void setUserFirstName(String userFirstName) {
this.userFirstName = userFirstName;
}
public String getUserLastName() {
return userLastName;
}
public void setUserLastName(String userLastName) {
this.userLastName = userLastName;
}
public String getUserMiddleName() {
return userMiddleName;
}
public void setUserMiddleName(String userMiddleName) {
this.userMiddleName = userMiddleName;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getUserAge() {
return userAge;
}
public void setUserAge(int userAge) {
this.userAge = userAge;
}
public String getUserSex() {
return userSex;
}
public void setUserSex(String userSex) {
this.userSex = userSex;
}
public Set<Address> getAddress() {
return address;
}
public void setAddress(Set<Address> address) {
this.address = address;
}
}
#Entity
#Table(name = "ADDRESS")
public class Address implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
#Id
#Column(name = "ADDRESS_ID")
#GeneratedValue(strategy=GenerationType.AUTO)
private int id;
#Column(name = "ZIP_CODE")
private String zipCode;
#Column(name="ADDRESS_USER_ID", insertable=false, updatable=false)
private Long addressUserID;
#Column(name = "ADDRESS_SEC")
private String addressSec;
#Column(name = "STREET")
private String street;
#Column(name = "CITY")
private String city;
#Column(name = "COUNTRY")
private String country;
#ManyToOne(cascade=CascadeType.ALL, targetEntity=User.class)
#JoinColumn(name="ADDRESS_USER_ID")
private Set<User> userAddress = new HashSet<User>();
public Long getAddressUserID() {
return addressUserID;
}
public void setAddressUserID(Long addressUserID) {
this.addressUserID = addressUserID;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getZipCode() {
return zipCode;
}
public void setZipCode(String zipCode) {
this.zipCode = zipCode;
}
public Set<User> getUserAddress() {
return userAddress;
}
public void setUserAddress(Set<User> userAddress) {
this.userAddress = userAddress;
}
public String getStreet() {
return street;
}
public void setStreet(String street) {
this.street = street;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getAddressSec() {
return addressSec;
}
public void setAddressSec(String addressSec) {
this.addressSec = addressSec;
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
}
Part of Stack Trace are:
Exception in thread "main" org.hibernate.PropertyAccessException: could not get a field value by reflection getter of com.java.hibernate.practise.User.id at... org.hibernate.property.DirectPropertyAccessor$DirectGetter.get(DirectPropertyAccessor.java:62)
Caused by: java.lang.IllegalArgumentException: Can not set int field com.java.hibernate.practise.User.id to java.util.HashSet...
I am generating the schema using hibernate.hbm2ddl.auto= cerate-drop
Please guide on this.
Generally when we use 1..n bidirectional entity mapping, the owning side which is in general, the many side, should have only a single instance reference to the one side object (not a collection - that would be many to many), and the join column to use is the primary key from the on side class. We don't need to explicitly use the FK column in the many side like you are.
So if this is your relationship User [1]..[N] Address, then you should have something more like
public class User {
...
#OneToMany(mappedBy = "user", cascade=CascadeType.ALL)
private Set<Address> addresses;
}
public class Address {
// private Long addressUserID; // Don't need this property. We get it below
...
#ManyToOne
#JoinColumn(name = "USER_ID")
private User user;
}