I'm attempting to use this dropwizard example and build off of it. I tried to add a column userName to the people table in Person.java like below
public class Person {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
#Column(name = "fullName", nullable = false)
private String fullName;
#Column(name = "jobTitle", nullable = false)
private String jobTitle;
#Column(name = "userName", nullable = false)
private String userName;
public Person() {
}
public Person(String fullName, String jobTitle, String userName) {
this.fullName = fullName;
this.jobTitle = jobTitle;
this.userName = userName;
}
I added the appropriate getters and setters, and equals method.
However I'm getting an error reading entity from input stream in this block.
#Test
public void testPostPerson() throws Exception {
final Person person = new Person("Dr. IntegrationTest", "Chief Wizard", "Dr. Wizard");
final Person newPerson = RULE.client().target("http://localhost:" + RULE.getLocalPort() + "/people")
.request()
.post(Entity.entity(person, MediaType.APPLICATION_JSON_TYPE))
--> .readEntity(Person.class);
assertThat(newPerson.getId()).isNotNull();
assertThat(newPerson.getFullName()).isEqualTo(person.getFullName());
assertThat(newPerson.getJobTitle()).isEqualTo(person.getJobTitle());
assertThat(newPerson.getUserName()).isEqualTo(person.getUserName());
}
the input stream error is caused by the following
Caused by: com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException:
Unrecognized field "code" (class com.example.helloworld.core.Person), not marked as ignorable (4 known properties: "fullName", "id", "userName", "jobTitle"])
will #JsonIgnoreProperties annotation at the class level solve this problem? Is this safe practice?
EDIT: PersonResource.java
#Path("/people/{personId}")
#Produces(MediaType.APPLICATION_JSON)
public class PersonResource {
private final PersonDAO peopleDAO;
public PersonResource(PersonDAO peopleDAO) {
this.peopleDAO = peopleDAO;
}
#GET
#UnitOfWork
public Person getPerson(#PathParam("personId") LongParam personId) {
return findSafely(personId.get());
}
#GET
#Path("/view_freemarker")
#UnitOfWork
#Produces(MediaType.TEXT_HTML)
public PersonView getPersonViewFreemarker(#PathParam("personId") LongParam personId) {
return new PersonView(PersonView.Template.FREEMARKER, findSafely(personId.get()));
}
#GET
#Path("/view_mustache")
#UnitOfWork
#Produces(MediaType.TEXT_HTML)
public PersonView getPersonViewMustache(#PathParam("personId") LongParam personId) {
return new PersonView(PersonView.Template.MUSTACHE, findSafely(personId.get()));
}
private Person findSafely(long personId) {
return peopleDAO.findById(personId).orElseThrow(() -> new NotFoundException("No such user."));
}
I think it's because the resource fails and throws a web application exception and code is actually the http status code.
Try it like this:
Response response = RULE.client().target("http://localhost:" + RULE.getLocalPort() + "/people")
.request()
.post(Entity.entity(person, MediaType.APPLICATION_JSON_TYPE));
assertEquals(200, response.getStatus());
Person newPerson = response.readEntity(Person.class);
....
You may also debug like this:
String responseString = response.readEntity(String.class);
Which will dump you the body of the response.
Related
I have 2 entitied (Post and FileUploads), the Post entity is responsible for a user to create an advert/post and the FileUploads entity is responsible for handling image uploads together with a post. (A post can have multiple FileUploads/Images associated with it).
The issue is that I get an error:
Column 'post_id' cannot be null
I'm unsure as to what's causing it, The PK in the FileUpload entity is a String and the Post entity PK is a Long, I don't know if that could be the cause?
I am auto-generating my Post PK as well.
FileUpload.java (Entity)
#Entity
#Table(name="file_upload")
public class FileUpload {
#Id
#GenericGenerator(name = "uuid", strategy = "uuid2")
#GeneratedValue(generator = "uuid")
#Column(name="id")
private String fileId;
private int imageCount;
private String name;
private String type;
private String fileUploader;
#Lob
private byte[] data;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name="post_id", nullable = false)
private Post post;
public FileUpload() {
}
public FileUpload(int imageCount, String name, String type, String fileUploader, byte[] data, Post post) {
this.imageCount = imageCount;
this.name = name;
this.type = type;
this.fileUploader = fileUploader;
this.data = data;
this.post = post;
}
Post.java (Entity)
Left out the other fields since i have a quite a bit
#Entity
public class Post {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#NotBlank(message = "Required")
#Size(max=45, message = "Maximum of 45 letters")
#Column(unique = true)
private String title;
private String postCreatorEmail;
private String postCreator;
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, mappedBy = "post")
private List<FileUpload> fileUploads = new ArrayList<>();
public Post() {
}
FileServiceImpl.java
Method to store images
#Service
public class FileUploadServiceImpl implements FileUploadService{
#Autowired
private FileUploadRepository fileUploadRepository;
#Autowired
private PostRepository postRepository;
private int imageCount;
#Override
public FileUpload uploadPostImage(MultipartFile file, String emailAddress) throws IOException {
Post thePost = postRepository.findPostByPostCreatorEmail(emailAddress);
String fileName = StringUtils.cleanPath(file.getOriginalFilename());
FileUpload fileDB = new FileUpload(++imageCount, fileName, file.getContentType(), emailAddress, file.getBytes(), thePost);
return fileUploadRepository.save(fileDB);
}
}
PostServiceImpl.java
#Service
public class PostServiceImpl implements PostService{
#Autowired
private PostRepository postRepository;
#Autowired
private UserRepository userRepository;
#Autowired
private FileUploadServiceImpl fileUploadService;
private int count;
#Override
public Post createOrUpdatePost(String post, String emailAddress){
// Removed update code
Post thePost = new Post();
try {
User user = userRepository.findUserByEmailAddress(emailAddress);
ObjectMapper objectMapper = new ObjectMapper();
thePost = objectMapper.readValue(post, Post.class);
user.setTotalAds(++count);
thePost.setPostCreator(user.getFullName());
thePost.setPostCreatorEmail(emailAddress);
thePost.setFileUploads(thePost.getFileUploads());
thePost.setUser(user);
userRepository.save(user);
return postRepository.save(thePost);
// The ad with the same title already exists - go to catch block
} catch (Exception e) {
throw new PostAlreadyExistsException("Post with title " + thePost.getTitle() + " already exists");
}
}
}
PostController.java (Only adding the handler method)
#PostMapping("/create")
public ResponseEntity<?> createPost(#RequestPart("file") MultipartFile file, #Valid #RequestPart String post, BindingResult result, Principal principal) {
ResponseEntity<?> errorMap = errorValidationService.validationService(result);
if(errorMap != null) return errorMap;
String message = "";
try {
fileUploadService.uploadPostImage(file, principal.getName());
postService.createOrUpdatePost(post, principal.getName());
message = "Uploaded the file successfully: " + file.getOriginalFilename();
return ResponseEntity.status(HttpStatus.OK).body(new ApiResponse(message, true));
} catch (Exception e) {
message = "Could not upload the file: " + file.getOriginalFilename() + "!";
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(new ApiResponse(message, false));
}
}
Postman results
Console output
Post DDL MySQL
FileUpload DDL MySQL
Try to add modify your uploadPostImage to this code:
#Override
public FileUpload uploadPostImage(MultipartFile file, String emailAddress) throws IOException {
Post thePost = postRepository.findPostByPostCreatorEmail(emailAddress);
// new part:
if (thePost == null) {
throw new RuntimeException("No post found yet for eMail-Address '" + emailAddress + "' to store images for!");
}
String fileName = StringUtils.cleanPath(file.getOriginalFilename());
FileUpload fileDB = new FileUpload(++imageCount, fileName, file.getContentType(), emailAddress, file.getBytes(), thePost);
return fileUploadRepository.save(fileDB);
}
Entity class
#Getter
#NoArgsConstructor
#Entity
public class Posts {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(length = 500, nullable = false)
private String title;
#Column(columnDefinition = "TEXT", nullable = false)
private String content;
private String author;
#Builder
public Posts(String title, String content, String author) {
this.title = title;
this.content = content;
this.author = author;
}
}
Test code
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class PostsAPIControllerTest {
#LocalServerPort
private int port;
#Autowired
private TestRestTemplate restTemplate;
#Autowired
private PostsRepository postsRepository; // PostsRepository extends JpaRepository<Posts, Long>
#After
public void tearDown() throws Exception {
postsRepository.deleteAll();
}
#Test
public void posts_save() throws Exception {
String title = "title";
String content = "content";
PostsSaveRequestDTO requestDTO = PostsSaveRequestDTO.builder()
.title(title)
.content(content)
.author("author")
.build();
String url = "http://localhost:" + port + "/api/v1/posts";
ResponseEntity<Long> responseEntity = restTemplate.postForEntity(url, requestDTO, Long.class);
assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.OK);
assertThat(responseEntity.getBody()).isGreaterThan(0L);
List<Posts> all = postsRepository.findAll();
assertThat(all.get(0).getTitle()).isEqualTo(title);
assertThat(all.get(0).getContent()).isEqualTo(content);
}
}
Controller
#RequiredArgsConstructor
#RestController
public class PostsAPIController {
private final PostsService postsService;
#PostMapping("/api/v1/posts")
public Long save(#RequestBody PostsSaveRequestDTO requestDTO) {
return postsService.save(requestDTO);
}
#PutMapping("/api/v1/posts/{id}")
public Long update(#PathVariable Long id, #RequestBody PostsUpdateRequestDTO requestDTO) {
return postsService.update(id, requestDTO);
}
#GetMapping("/api/v1/posts/{id}")
public PostsResponseDTO findById(#PathVariable Long id) {
return postsService.findById(id);
}
}
I made a sample Spring Boot test code that updates DB, but test fails with following error message if I execute the code. I already defined spring.security.user.name and spring.security.user.password to application.properties file.
What is the problem? I tried to reload after removing testImplementation 'org.springframework.security:spring-security-test' from build.gradle, but nothing has changed.
Expecting:
<401 UNAUTHORIZED>
to be equal to:
<200 OK>
but was not.
There are multiple ways to mock the security using #WithMockUser, #WithAnonymousUser, #WithUserDetails, #WithSecurityContext. You can use these annotations with #Test method
You may change the roles as required in the project. You may like to explore more details here
#Test
#WithMockUser(username="admin",roles="ADMIN")
public void posts_save() throws Exception {
String title = "title";
String content = "content";
PostsSaveRequestDTO requestDTO = PostsSaveRequestDTO.builder()
.title(title)
.content(content)
.author("author")
.build();
String url = "http://localhost:" + port + "/api/v1/posts";
ResponseEntity<Long> responseEntity = restTemplate.postForEntity(url, requestDTO, Long.class);
assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.OK);
assertThat(responseEntity.getBody()).isGreaterThan(0L);
List<Posts> all = postsRepository.findAll();
assertThat(all.get(0).getTitle()).isEqualTo(title);
assertThat(all.get(0).getContent()).isEqualTo(content);
I'm working on a Spring Boot + Maven + Restful + Hibernate project! After creating the RestController for adding new Devices in database i'm getting this error:
2018-03-28 10:15:18.786 WARN 9286 --- [nio-9090-exec-9] .w.s.m.s.DefaultHandlerExceptionResolver : Failed to read HTTP message: org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot construct instance of `com.hhm.hsy.hibernate.models.Protocol` (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('{"id":5,"protocolName":"ProtocolForTesting","port":5202}'); nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot construct instance of `com.hhm.hsy.hibernate.models.Protocol` (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('{"id":5,"protocolName":"ProtocolForTesting","port":5202}')
at [Source: (PushbackInputStream); line: 1, column: 52] (through reference chain: com.hhm.hsy.hibernate.models.Device["protocol"])
Here is my first entity:
#Entity
#Table(name = "devices", catalog = "hqm")
public class Device implements Serializable {
private static final long serialVersionUID = -8311225474375837513L;
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "device_id", unique = true, nullable = false)
private Integer id;
#Column(name = "device_name", unique = true, nullable = false)
private String deviceName;
#ManyToOne
#JoinColumn(name = "protocol_id")
private Protocol protocol;
public Device() {
}
public Device(Integer id, String deviceName, Protocol protocol) {
this.id = id;
this.deviceName = deviceName;
this.protocol = protocol;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getDeviceName() {
return deviceName;
}
public void setDeviceName(String deviceName) {
this.deviceName = deviceName;
}
public Protocol getProtocol() {
return protocol;
}
public void setProtocol(Protocol protocol) {
this.protocol = protocol;
}
And the second entity:
#Entity
#Table(name = "protocols", catalog = "hqm")
public class Protocol implements Serializable {
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "protocol_id", unique = true, nullable = false)
private Integer id;
#Column(name = "protocol_name", unique = true, nullable = false, length = 45)
private String protocolName;
#Column(name = "port", nullable = false)
private Integer port;
#OneToMany(mappedBy = "protocol", cascade = CascadeType.ALL, orphanRemoval = true)
private Set<Device> devices = new HashSet<>();
public Protocol() {
}
public Protocol(Integer id, String protocolName, Integer port) {
this.id = id;
this.protocolName = protocolName;
this.port = port;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getProtocolName() {
return protocolName;
}
public void setProtocolName(String protocolName) {
this.protocolName = protocolName;
}
public Integer getPort() {
return port;
}
public void setPort(Integer port) {
this.port = port;
}
#JsonIgnore
public Set<Device> getDevices() {
return devices;
}
#JsonIgnore
public void setDevices(Set<Device> devices) {
this.devices = devices;
}
}
Controller:
#RestController
#RequestMapping(value = "/api/devices")
#ComponentScan({"com.hhm.hsy.pmcs.*"})
public class DevicesController {
#Autowired
#Qualifier(value = "deviceService")
GenericServiceIntf deviceService;
// get ALL DEVICE
#RequestMapping(value = "", method = RequestMethod.GET)
public Map<String, Object> getDevices() {
Map<String, Object> devicesMap = new HashMap<>();
devicesMap.put("devices", deviceService.getAll());
return devicesMap;
}
//save a new DEVICE
#RequestMapping(value = "", method = RequestMethod.POST, consumes = {"application/json"}, produces = {"application/json"})
#ResponseStatus(HttpStatus.CREATED)
public ResponseEntity<Device> addDevice(#RequestBody Device device) {
deviceService.save(device);
return ResponseEntity.accepted().body(device);
}
}
Service:
#Service("deviceService")
public class DeviceServiceImpl extends GenericServiceAbstractImpl<Device, Integer> implements Serializable{
private static final long serialVersionUID = 697655212967127150L;
#Autowired
public DeviceServiceImpl(#Qualifier("deviceDao") GenericDaoIntf genericDao) {
super(genericDao);
}
}
So when i'm trying to add a new device, i get the error i mentioned upper.I don't know what is causing this exception. When I try to add with post a new Protocol it's working, table is being created in the database correctly and I am getting the data correctly in GET request as well..Please help me, I'm new to springboot and restful... if some more information is required, please just inform me and i will post it! Thank you!
I tried to reproduce your problem: here, but everything works as expected.
I think it can be related with this bug.
You should try to reproduce bug with different jackson version.
EDIT:
One more thing: It looks like you try to construct Protocol instead of Device. Show us your deviceService, if you can.
Failed to read HTTP message:
org.springframework.http.converter.HttpMessageNotReadableException:
JSON parse error: Cannot construct instance of
`com.hhm.hsy.hibernate.models.Protocol
I am want to validate a JSON object, for length of an attribute. I am using #Size annotation to specify maximum length as shown below.
#JsonRootName("question")
public class QuestionJson {
#JsonProperty(value = "id", required = false)
private Long id;
#JsonProperty(value = "text", required = true)
private String label;
#JsonProperty(value = "answers", required = true)
private List<AnswerJson> answers;
}
#JsonRootName("answer")
public class AnswerJson {
#JsonProperty(value = "id", required = false)
private Long id;
#JsonProperty(value = "type", required = true)
private String type;
#JsonProperty(value = "label", required = true)
#Size(message = "size should not be long", max = 10)
private String label;
}
My request mapping in controller looks like:
#RequestMapping(value = "/api/answer", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_UTF8_VALUE)
public AnswerJson createQuestion(#RequestHeader(HttpHeaders.AUTHORIZATION) final String authorizationHeader, #Valid #RequestBody final QuestionJson questionJson) {
// some code here....
return answer;
}
UPDATE: Validation works on the outer elements eg. text in my case but fails on the nested list.
Every time we use #Valid annotation we also include a BindingResult instance as a method parameter, it contains the #Valid marked parameter errors if any:
public final #ResponseBody String theMethod(
final #Valid ValidableObjectImpl validableObject,
BindingResult result) {
try {
if (result.hasErrors()) {
for (FieldError error : result.getFieldErrors()){
// do something
}
// return error
}
} catch (Exception e) {
// ...
}
}
Found the solution. We need add #Valid annotation to the before the declaration of the nested object. eg
#JsonRootName("question")
public class QuestionJson {
#JsonProperty(value = "id", required = false)
private Long id;
#JsonProperty(value = "text", required = true)
private String label;
#JsonProperty(value = "answers", required = true)
#Valid
private List<AnswerJson> answers;
}
I have User entity and a field Role in this entity. Role is ENUM. I am trying to create user from UI. However, i am getting an exception:
org.springframework.beans.NullValueInNestedPathException: Invalid property 'role' of bean class [com.bionic.entities.User]: Could not instantiate property type [com.bionic.entities.Role] to auto-grow nested property path: org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.bionic.entities.Role]: Is it an abstract class?; nested exception is java.lang.InstantiationException: com.bionic.entities.Role
Here is my Role.Enum:
package com.bionic.entities;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
#Resource
public enum Role {
ADMINISTRATOR(1, "administrator"),
TRAINER(2, "trainer"),
STUDENT(3, "student"),
RESTRICTED_ADMINISTRATOR(4, "restricted_administrator"),
RESTRICTED_TRAINER(5, "restricted_trainer");
private long id;
private String name;
Role(){}
private Role(long id, String name) {
this.name = name;
this.id = id;
}
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;
}
}
My User.class fields:
public class User {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
#Column(name = "first_name", nullable = false)
private String firstName;
#Column(name = "last_name", nullable = false)
private String lastName;
#Column(name = "email", nullable = false, unique = true)
private String email;
#Column(name = "password", nullable = false)
private String password;
#Column(name = "cell")
private String cell;
#Column(name="position")
private String position;
#Enumerated(EnumType.ORDINAL)
#Column(name = "role_id")
private Role role;
and, finally, my html form:
<form method="POST" action="/superAdmin/addUser" th:object="${user}">
<select name="role.id" size="2" th:field="*{role.id}" style="display: block" id="role.id"></select>
<br /> <br /> <input type="submit" value="Upload" class="submit-but">
I've spent 2 days in order to solve that. however, it wasn't successful
How am i creating entity after:
#RequestMapping(value = "/addUser", method = RequestMethod.POST)
public
#ResponseBody
String addUser(#ModelAttribute User user, Model model) {
try {
model.addAttribute("user", user);
superAdministratorService.addUser(user);
return "successful";
} catch (Exception e) {
return "You failed to upload";
}
}
Role has a default package-level constructor and a private constructor with 2 arguments, try to change your package-level constructor to public in order to do that, change
Role(){}
by
public Role(){}
I think this is the cause of your problem. But you cannot set a public constructor in enum, so maybe you must change your implementation to a final class.
UPDATE
public static Role fromId(long id) {
if (1 == id) {
return ADMINISTRATOR;
}
// TODO else if for the rest of enum instances
} else {
throw new AssertionError("Role not know!");
}
}
A possible solution for that would be the following:
Use a DTO (simple POJO with the same properties that the User entity and getters and setters) to receive the object in addUser method, in that DTO define role as integer.
In your enum, create a method like the one above
Create the entity object from de DTO object, using the method above to set the role member in User entity.