My code is something like:
#XmlRootElement
#XmlType(propOrder = {"id", "name", "content", "disclaimer", "buttons"})
public class Product {
private String id;
private String name;
private String content;
private String disclaimer;
private List<ProductButton> buttons = new ArrayList<ProductButton>();}
Service code is:
#GET
#Produces(MediaType.APPLICATION_JSON)
#Path("/GetProduct")
public Response getProduct() {
try {
Product product = generateProductById(productId);
return Response.ok().entity(product).build();
}
catch (Exception e) {
log.error(e.getLocalizedMessage(), e);
return Response.serverError().build();
}
}
However the output json string is not in order.
My expected order is same as my object, however the result is: "name", "id", "content"...
Anyone got idea how i can achieve that?
--------------------------------------Updated--------------------------------
#JsonPropertyOrder({"id", "name", "content", "disclaimer", "buttons"})
public class Product {
private String id;
private String name;
private String content;
private String disclaimer;
private List<ProductButton> buttons = new ArrayList<ProductButton>();}
Use the resteasy-jackson-provider and then annotate your class with the #JsonPropertyOrder annotation.
Here is the Maven dependency for the provider. If you are not using Maven just add this jar to your classpath.
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jackson-provider</artifactId>
<version>${resteasy.version}</version>
</dependency>
Example:
#JsonPropertyOrder({
"user_id",
"user_name",
"email"
})
public class User
{
#JsonProperty("user_id")
private Long userId;
#JsonProperty("user_name")
private String username;
private String email;
//Getters and Setters Removed for Brevity
}
Related
I have the following Spring Boot MySQL query:
visitorrepository.save(newvisitor)
Upon execution of this MySQL query, I want to return a success JSON or failure JSON in the following format:
Success State:
{
"success": true,
"message": "Some Helpful Message",
"data": { } //This would be the newvisitor JSON that includes the primary key (id)
}
Failure State:
{
"success": false,
"message": "Some Helpful Message",
"error_code": "404", // This should be whatever error number was returned
"data": { } //This would be the newvisitor JSON that does not include the primary key (id)
}
In angular the response is captured as follows
this.http.post('http://localhost:8080/v1/api/post', this.visitor.value).toPromise().then((response:any) => {
console.log(response);
})
post.java
#CrossOrigin(origins = "http://localhost:4200")
#RestController
public class post {
#Autowired
visitorrepository visitorrepository;
#PostMapping("/v1/api/post")
public void insert(#Valid #RequestBody newvisitor newvisitor) {
try {
visitorrepository.save(newvisitor);
return // Success State JSON
} catch () {
return // Error State JSON
}
}
}
newvisitor.java
#Getter
#Setter
#Entity
#Table(name = "visitors")
public class newvisitor {
#Id
#GeneratedValue
private Long id;
#Size(min=1, max=250)
#NotBlank
private String firstname;
#NotBlank
private String lastname;
#NotBlank
private String month;
#NotBlank
private String day;
#NotBlank
private String year;
#NotBlank
private String socialsecuritynumber;
#NotBlank
private String street1;
private String street2;
#NotBlank
private String city;
#NotBlank
private String state;
#NotBlank
private String zip;
#NotBlank
private String phone;
#Email
#NotBlank
private String email;
public newvisitor(){
super();
}
public newvisitor(String firstname, String lastname, String month, String day, String year, String socialsecuritynumber, String street1, String street2, String city, String state, String zip, String phone, String email) {
super();
this.firstname = firstname;
this.lastname = lastname;
this.month = month;
this.day = day;
this.year = year;
this.socialsecuritynumber = socialsecuritynumber;
this.street1 = street1;
this.street2 = street2;
this.city = city;
this.state = state;
this.zip = zip;
this.phone = phone;
this.email = email;
}
}
visitorrepository.java
#Repository
public interface visitorrepository extends CrudRepository<newvisitor, Long> {
}
The thought is to catch everything from MySQL database not connecting, to invalid data entry, to duplicate records, bascially anything that prevented the initial query visitorrepository.save(newvisitor) from working, and return this to angular as a JSON. I feel like ResponseEntity or RestControllerAdvice might be the answer, just not sure best way to implement if this is accurate.
You already have the answer.
I feel like ResponseEntity or RestControllerAdvice might be the answer
You only create a dto response with your format. then put it in ResponseEntity in case error or not.
I'm attempting to deserialize this json in my Spring Boot server application (which uses Jackson). Its throws an com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field. The prefix seems to be an issue and I can tell Jackson to ignore the user_metadata field and it works fine, however I do need to access that value. I've had a look through the various Spring #Json annotations and none seem to deal with the prefix.
{
"sub":"",
"nickname":"",
"name":"",
"picture":"",
"updated_at":"2020-05-01T11:23:01.110Z",
"email":"",
"email_verified":false,
"https://somedomain:eu:auth0:com/user_metadata":{
"tennant":"value"
}
}
And the model classes in Java
public class UserMetaData {
private String tennant;
public String getTennant() {
return tennant;
}
public void setTennant(String tennant) {
this.tennant = tennant;
}
}
public class UserInfo {
private String email;
private String sub;
private String picture;
private String nickname;
private Date updated_at;
private boolean email_verified;
private UserMetaData user_metadata;
private String name;
}
Getters and setters removed for brevity
Stack trace below:-
com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "https://raptorsoftware:eu:auth0:com/user_metadata" (class uk.co.raptorsoftware.domain.UserInfo), not marked as ignorable (8 known properties: "sub", "user_metadata", "updated_at", "name", "email", "picture", "email_verified", "nickname"])
at [Source: (String)"{"sub":"","nickname":"darren.roberts","name":"","picture":"https://s.gravatar.com/avatar/c496e319edc303163f2e87e5ca91507d?s=480&r=pg&d=https%3A%2F%2Fcdn.auth0.com%2Favatars%2Fda.png","updated_at":"2020-05-01T16:39:11.271Z","email":"darren.roberts#","email_verified":false,"https://raptorsoftware:eu:auth0:com/user_metadata":{"tennant":"some value"}}"; line: 1, column: 411] (through reference chain: uk.co.raptorsoftware.domain.UserInfo["https://raptorsoftware:eu:auth0:com/user_metadata"])
at com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException.from(UnrecognizedPropertyException.java:61) at com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException.from(UnrecognizedPropertyException.java:61)
at com.fasterxml.jackson.databind.DeserializationContext.handleUnknownProperty(DeserializationContext.java:840)
at com.fasterxml.jackson.databind.deser.std.StdDeserializer.handleUnknownProperty(StdDeserializer.java:1206)
at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.handleUnknownProperty(BeanDeserializerBase.java:1592)
at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.handleUnknownVanilla(BeanDeserializerBase.java:1570)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:294)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:151)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4202)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3205)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3173)
at uk.co.raptorsoftware.web.BaseController.getUserInfo(BaseController.java:49)
at uk.co.raptorsoftware.web.MemberController.listMembers(MemberController.java:49)'''
The problem is the url as key of the UserMetaData. Try to use #JsonProperty
public class UserInfo {
private String email;
private String sub;
private String picture;
private String nickname;
private Date updated_at;
private boolean email_verified;
#JsonProperty(name="https://somedomain:eu:auth0:com/user_metadata")
private UserMetaData user_metadata;
private String name;
}
I am a running a project with SpringBoot. In this project I am calling an external Rest Service. I have modeled the response items into bean.
But when I get the response back the data are not serialised into the beans.
I guess there must be some configuration missing but I cannot find what.
I have added onfiguration spring-boot-starter-test to the configuration of Maven:
The rest client:
#RunWith(SpringRunner.class)
#SpringBootTest
public class RestClientTest {
#Autowired
private RestTemplateBuilder restTemplate;
#Test
public void sayHello() {
System.out.println("Hello");
assert(true);
}
#Test
public void testGetEmployee() {
RestTemplate template = restTemplate.build();;
HttpHeaders headers = new HttpHeaders();
List<MediaType> types = new ArrayList<MediaType>();
types.add(MediaType.APPLICATION_JSON);
types.add(MediaType.APPLICATION_XML);
headers.setAccept(types);
headers.set("Authorization", "Bearer gWRdGO7sUhAXHXBnjlBCtTP");
HttpEntity<Items> entity = new HttpEntity<Items>(headers);
String uri = "https://mytest.com/employees";
//ResponseEntity<String> rec = template.exchange(uri, HttpMethod.GET, entity, String.class);
//System.out.println("Received: " + rec);
ResponseEntity<Items> rec = template.exchange(uri, HttpMethod.GET, entity, Items.class);
System.out.println("Received: " + rec);
}
}
When I inspect the elements of the response it, I get a list, all the items are with null values
#JsonFormat(shape = JsonFormat.Shape.OBJECT)
public class Item implements Serializable {
#JsonProperty
private String id;
#JsonProperty
private String name;
#JsonProperty
private String email;
#JsonProperty
private String phone;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
}
#JsonFormat(shape = JsonFormat.Shape.OBJECT)
public class Items implements Serializable {
#JsonProperty
private List<Item> items = new ArrayList<Item>();
public List<Item> getItems() {
return items;
}
}
Do you see what I am missing here?
The response is like this:
{
"items": [
{
"item": {
"id": 0,
"name": "string",
"email": "string",
"phone": "string",
Do you see what I am missing here?
Thanks
Gilles
The way you have implemented will try to deserialize data into Items class. But it doesn't have the required properties to deserialize. When you need to get a list of data through rest template exchange, you can get them as follows.
Get data as an array and convert it into arrayList.
Item[] itemArray = template.exchange(uri, HttpMethod.GET, entity, Item[].class).getBody();
List<Item> itemList = Arrays,asList(itemArray);
or
Use ParameterizedTypeReference to get data as a list
ResponseEntity<List<Item>> itemList = template.exchange(uri, HttpMethod.GET, entity, new ParameterizedTypeReference<List<Item>>() {});
List<Item> itemList = template.exchange(uri, HttpMethod.GET, entity, new ParameterizedTypeReference<List<Item>>() {}).getBody(); // access list directly
You might need to add this to your ObjectMapper:
mapper.configure(DeserializationFeature.UNWRAP_ROOT_VALUE, true);
And on your entity add #JsonRootName("item")
In model class I have isActive field with is boolean, that represent the is_active field in MySql DB. Here is whole model class:
package ca.gatin.model;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
#Entity
#Table(name = "Account")
public class Account {
#Id
#GeneratedValue
private Long id;
#Column(name = "first_name")
private String firstName;
#Column(name = "last_name")
private String lastName;
#Column(nullable = false, unique = true)
private String email;
#Column(nullable = false)
private String password;
#Column(name = "is_active", nullable = false)
private boolean isActive;
#Column(name = "date_created")
private Date dateCreated;
#Column(name = "date_last_modified")
private Date dateLastModified;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public boolean isActive() {
return isActive;
}
public void setActive(boolean isActive) {
this.isActive = isActive;
}
public Date getDateCreated() {
return dateCreated;
}
public void setDateCreated(Date dateCreated) {
this.dateCreated = dateCreated;
}
public Date getDateLastModified() {
return dateLastModified;
}
public void setDateLastModified(Date dateLastModified) {
this.dateLastModified = dateLastModified;
}
}
But when I fetch account let's say through REST API like:
#RequestMapping(
value = "/{id}",
method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE)
public ServiceResponse<Account> getAll(#PathVariable("id") Long id) {
ServiceResponse<Account> serviceResponse = accountService.getAccountById(id);
return serviceResponse;
}
In a reply object I get isActive field renamed by Hibernate to "active" like this:
{
"id": 19,
"firstName": "Julia",
"lastName": "Sarandi",
"email": "julia#gatin.ca",
"password": "111111",
"dateCreated": 1451293826000,
"dateLastModified": null,
"active": true
}
Why? Why all other field's names stay same as in Account class, but isActive is renamed?
That is one question, and another question is:
I am new in Hibernate, and I do no understand why in logs of Hibernate DB requests is shows some weird queries:
Hibernate: select account0_.id as id1_0_0_, account0_.date_created as date_cre2_0_0_, account0_.date_last_modified as date_las3_0_0_, account0_.email as email4_0_0_, account0_.first_name as first_na5_0_0_, account0_.is_active as is_activ6_0_0_, account0_.last_name as last_nam7_0_0_, account0_.password as password8_0_0_ from Account account0_ where account0_.id=?
What query language is it? What are symbols: "0_", "0_0_". Can I switch logs to show MySQL queries to make it more understandable?
FYI
In my application.properties file I have following configuration:
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect
spring.jpa.hibernate.naming-strategy=org.hibernate.cfg.DefaultNamingStrategy
Change getter and setter method name for isActive field as:
public boolean getIsActive() {
return isActive;
}
public void setIsActive(boolean isActive) {
this.isActive = isActive;
}
Then it return isActive in response.
That has nothing to do with Hibernate, and everything to do with your JSON marshaller. Spring uses Jackson, and Jackson uses bean properties (i.e. getters) to access the data and transform them to JSON fields. Your getter is named isActive(), and thus corresponds to a bean property named active, hence the name of the attribute in the JSON.
If you want the JSON field to be named isActive, then your getter should be isIsActive(). Or much better, you should annotate it with #JsonProperty("isActive").
To answer your second question, the query is a SQL query, generated by Hibernate. It changes the name of tables and assigns aliases to columns mainly to disambiguate tables, and fields of different tables that could have the same name, AFAIK.
I am new to Dropwizard and so far everything was going well till I started messing with Hibernate and MySQL. My problem is: Hibernate won't create tables and consequently no columns in my DB.
The only warning I get when running my jar file is:
org.hibernate.cfg.environment hibernate.properties not found
But do I need it at all? As I am having all configuration and mapping already.
Here is my application class:
public class LibraryApplication extends Application<LibraryConfiguration> {
public static void main(String[] args) throws Exception {
new LibraryApplication().run(args);
}
#Override
public String getName() {
return "hello backend";
}
private final HibernateBundle<LibraryConfiguration> hibernate = new HibernateBundle<LibraryConfiguration>(Book.class){ //more entities can be added separated with a coma
public DataSourceFactory getDataSourceFactory(LibraryConfiguration configuration) {
return configuration.getDataSourceFactory();
}
};
#Override
public void initialize(Bootstrap<LibraryConfiguration> bootstrap) {
bootstrap.addBundle(new AssetsBundle("/webapp", "/", "index.html", "static"));
bootstrap.addBundle(hibernate);
}
#Override
public void run(LibraryConfiguration configuration,
Environment environment) {
final BookDAO dao = new BookDAO(hibernate.getSessionFactory());
final TestResource resource = new TestResource(
configuration.getTemplate(), configuration.getDefaultName());
final TemplateHealthCheck healthCheck = new TemplateHealthCheck(
configuration.getTemplate());
environment.healthChecks().register("template", healthCheck); //register the health check
environment.jersey().register(resource); //register the resource class
environment.jersey().register(new BookResource(dao));
}
}
YAML file:
server:
type: simple
rootPath: '/api/*'
applicationContextPath: /
connector:
type: http
port: 8080
template: Hello, %s!
defaultName: back-end
database:
# the name of your JDBC driver
driverClass: com.mysql.jdbc.Driver
# the JDBC URL
url: jdbc:mysql://localhost:3306/books
# the username
user: root
# the password
password: root
# any properties specific to your JDBC driver:
properties:
charSet: UTF-8
hibernate.dialect: org.hibernate.dialect.MySQLDialect #org.hibernate.dialect.MySQL5InnoDBDialect
hibernate.hbm2ddl.auto: create
Configurtion class:
public class LibraryConfiguration extends Configuration{
#Valid
#NotNull
#JsonProperty
private DataSourceFactory database = new DataSourceFactory();
#JsonProperty("database")
public DataSourceFactory getDataSourceFactory() {
return database;
}
#NotEmpty
private String template;
#NotEmpty
private String defaultName = "";
#JsonProperty
public String getTemplate() {
return template;
}
#JsonProperty
public void setTemplate(String template) {
this.template = template;
}
#JsonProperty
public String getDefaultName() {
return defaultName;
}
#JsonProperty
public void setDefaultName(String name) {
this.defaultName = name;
}
}
and my entity:
#Entity
#Table(name = "book")
#NamedQueries({
#NamedQuery(
name = "library.core.Book.findAll",
query = "SELECT b FROM book b"
)
})
public class Book{
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column
private Long id;
#Column(name = "title")
#NotNull
private String title;
#Column(name = "author")
#NotNull
private String author;
#Column(name = "date")
private long date;
#Column(name = "description")
private String description;
#Column(name = "image")
private String image;
public Book(String title, String author){
this.title = title;
this.author = author;
}
#JsonProperty
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
#JsonProperty
public Long getId() {
return id;
}
#JsonProperty
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
#JsonProperty
public long getDate() {
return date;
}
public void setDate(long date) {
this.date = date;
}
#JsonProperty
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
#JsonProperty
public String getImage() {
return image;
}
public void setImage(String image) {
this.image = image;
}
public void setId(Long id) {
this.id = id;
}
}
I have already been to many tutorials but none of them really explains how to configure hibernate. Thank you in advance.
I have finally solved this problem, which was not a big deal actually. Just a small mistake as it was expected.
My problem was a Book class, IDE automatically imported the java library called Book in the LibraryApplication class, so DB was not mapping it.
On the other hand, in the Book class the named query should be as follows:
#NamedQuery(
name = "library.core.Book.findAll",
query = "SELECT b FROM Book b"
)
My mistake: I was writing Book with small letter.