Spring mvc, fileds not in form will get cleared because of null value - mongodb

I have a simple POJO:
#Document(collection = "questions")
public class Question {
private String title;
private Date createdAt;
//..... all the getter and setters
}
I did not add the createdAt on the edit form, because it should not be changed after creation. But the update controller method will get a null value in createdAt due to the binding.
#RequestMapping(method = RequestMethod.PUT, produces = "text/html")
public String update(#Valid Question question, BindingResult bindingResult,
Model uiModel, HttpServletRequest httpServletRequest) {
if (bindingResult.hasErrors()) {
populateEditForm(uiModel, question);
return "questions/update";
}
uiModel.asMap().clear();
questionRepository.save(question);
return "redirect:/questions/"
+ encodeUrlPathSegment(question.getId().toString(),
httpServletRequest);
}
So after updating the Question, the createdAt field will get cleared. Any idea how to solve it? I don't want to create another class without createdAt field and do the update.

You could add a hidden field in your form, pre-populated with createdAt.

Related

Spring Data - MongoRepository - #Query to find item within nested list of objects

I'm trying to query MongoDB to return a single Answer object contained within a QuestionDocument object.
I am using Spring, MongoRepository, and JDK 11.
My QuestionDocument POJO:
#Data
#Document(collection = "Questions")
#AllArgsConstructor(onConstructor = #__(#Autowired))
#NoArgsConstructor
public class QuestionDocument {
#Id
private String questionId;
(...)
private List<Answer> answers;
(...)
}
My Answer POJO:
#Data
public class Answer implements Serializable {
private String answerId;
(...)
My QuestionRepository:
#Repository
public interface QuestionRepository extends MongoRepository<QuestionDocument, String> {
#Query(value = "{ { 'questionId' : ?0 }, { 'answers.$answerId' : ?1 } }")
Answer findByQuestionIdAndAnswerId(String questionId, String answerId);
My QuestionServiceImpl:
public getAnswer(String questionId, String answerId){
Answer answer = findByQuestionIdAndAnswerId(questionId, answerId);
return answer;
}
protected Answer findByQuestionIdAndAnswerId(String questionId, String answerId){
Answer answer;
try {
answer = questionRepository.findByQuestionIdAndAnswerId(questionId, answerId);
} catch (Exception e) {
throw new IllegalArgumentException("There is no answer with this ID.");
}
return answer;
}
When I hit my endpoint in Postman, the correct response body appears, but all of its values are null. I have verified that the correct questionId and answerId are passed in my parameters.
I have also consulted several additional SO posts and Spring and MongoDB documentation, but so far, implementing what I've read regarding traversing nested objects by property hasn't helped.
How does my #Query value need to change to properly return a specific Answer object from this nested list of answers?
I have attempted to create findBy methods like:
findByQuestion_Answers_AnswerId(String answerId);
I have attempted to add #DBRef above my List<Answer> answers, and adding #Document(collection = "Answers") and #Id above private String answerId; in my Answer POJO. I then cleared my database, created a new question and answer, and queried for the specific answerId, and still returned null data.
What I expect, is that given the questionId and answerId, the query will return one Answer object and its associated information (answerBody, answerAuthor, etc.).
My postman response states SUCCESS, but the data is null.
You can change the Query to this.
#Query(value = "{{'questionId' : ?0, 'answers.answerId' : ?1}}")
or, just define this method.
findByQuestionIdAndAnswerId(String questionId, String answerId);
The return type will be of QuestionDocument, not Answer.
More details here.

Spring Data update mongodb Document with DBRF lazy attribute

I want to update a MongoDB document containing a dbrf lazy attribute using spring data.
First of all, I load the existing document, I change the attributes I want and after that, I call #Repository save method, but when I check the document in MongoDB the dbrf lazy attribute is null.
I tried to load the attribute before by calling getAttribute, but that doesn't fix the problem.
Someone could help me?
Thanks
I have the Collection below:
#Data
#Document(collection = "calendriers")
public class CalendrierEntity {
#Id
#AutoGenerate(SequanceKey.CALENDRIER)
private Long id;
#NotNul
private String label;
#NotNull
private HorairesEntity horairesEntity;
#DBRef(lazy = true)
#CascadeSave
#Getter(AccessLevel.NONE)
private List<AbsenceEntity> absenceEntities;
}
and the repository bellow :
#Repository
public interface AbsenceRepository extends MongoRepository<CalendrierEntity, Long> {
AbsenceEntity findById(Long enfantId, LocalDate localDate);
}
I have calendrier document with Id 1L and want to update his label.
The calendrier document have allready a list of Absences.
this my code to update the label.
#Transactional
public void updateLabelCalendrier(Long id, String label){
CalendrierEntity calendrier = calenderRepository.findById(1L);
calendrier.setLabel(label);
calenderRepository.save(calendrier);
}
but when i check data in mongodb, i have the new label but my list of absences became null.

Spring boot REST application

I am trying to make a RESTful application in Java using Spring boot by following the tutorial here. I want to modify it so that I can extract an identifier from the URL and use it to serve requests.
So http://localhost:8080/members/<memberId> should serve me a JSON object with information about the member whose ID is <memberId>. I don't know how to
Map all http://localhost:8080/members/* to a single controller.
Extract the from the URL.
Should the logic of extracting the memberId and using it be part of the controller or a separate class, as per the MVC architecture?
I am new to Spring/Spring-boot/MVC. It is quite confusing to get started with. So please bear with my newbie questions.
Map all http://localhost:8080/members/* to a single controller.
You can use a placeholder in a request mapping to so it'll handle multiple URLs. For example:
#RequestMapping("/members/{id}")
Extract the id from the URL
You can have the value of a placeholder injected into your controller method using the #PathVariable annotation with a value that matches the name of the placeholder, "id" in this case:
#RequestMapping("/members/{id}")
public Member getMember(#PathVariable("id") long id) {
// Look up and return the member with the matching id
}
Should the logic of extracting the memberId and using it be part of the controller or a separate class, as per the MVC architecture?
You should let Spring MVC extract the member id from the URL as shown above. As for using it, you'll probably pass the URL to some sort of repository or service class that offers a findById method.
As you can see in the code below, service for customer are in one controller to get one and to add new customer.
So, you will have 2 services:
http://localhost:8080/customer/
http://localhost:8080/customer/{id}
#RestController("customer")
public class SampleController {
#RequestMapping(value = "/{id}", method = RequestMethod.GET)
public Customer greetings(#PathVariable("id") Long id) {
Customer customer = new Customer();
customer.setName("Eddu");
customer.setLastname("Melendez");
return customer;
}
#RequestMapping(value = "/{id}", method = RequestMethod.POST)
public void add(#RequestBody Customer customer) {
}
class Customer implements Serializable {
private String name;
private String lastname;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void setLastname(String lastname) {
this.lastname = lastname;
}
public String getLastname() {
return lastname;
}
}
}

Spring mongodb get ID of inserted item after Save

I am working with Spring MongoDb.
I create various entities using insert method:
http://docs.spring.io/spring-data/mongodb/docs/current/api/org/springframework/data/mongodb/core/MongoOperations.html#insert-java.lang.Object-
However, all methods return void. I need to return the ObjectId of the inserted document.
What is the best way to get it?
This is pretty interesting and thought I would share. I just figured out the solution for this with the help of BatScream comment above:
You would create an object and insert it into your MongoDB:
Animal animal = new Animal();
animal.setName(name);
animal.setCat(cat);
mongoTemplate.insert(animal);
Your animal class looks like this with getters and settings for all fields:
public class Animal {
#Id
#JsonProperty
private String id;
#JsonProperty
private String name;
#JsonProperty
private String cat;
public String getId() {
return id;
}
}
AFTER you have done the insert under mongoTemplate.insert(animal);, you can actually call the method animal.getId() and it will return back the ObjectId that was created.
I had the same problem with #AlanH that animal.getId() is null. And then I just realized my id field had been set as a final field with a wither method. So of course getId() is null since the id field is immutable and the wither method returns a new object with id.
if this is the case: use animal = template.insert(animal).

Entity Framework, unmapped property and Dynamic Data

I'm using an Entity Framework data model to drive a Dynamic Data website for use by users to update data.
One of the entities contains a non-nullable string property (Description). In the database, one of the rows has an empty Description (not null but an empty string). When I try to update the Description I get the following validation error: "This property cannot be set to a null value".
If I manually update the Description in the database and then edit the property, it works as expected. But as soon as I change the Description in the database back to an empty string, the validation error occurs. The error happens on Description's setter.
So I've tried adding an additional string property called CustomDescription which basically wraps Description, made Description a ScaffoldColumn(false) in the entity's metadata and added the new property to the entity's metadata.
[ScaffoldColumn(true)]
public string CustomDescription
{
get { return this.Description; }
set {
if (value == null)
{
value = string.Empty;
}
this.Description = value;
}
}
However what do I need to add to this property in order to get it to display on the dynamic data site?
Problem is that old value was empty string in Non-Nullable field.
By default framework is converting it to null.
To fix the error just add the following attribute to your field:
[DisplayFormat(ConvertEmptyStringToNull = false)]
public object Description { get; set; }
In the corresponding Metadata class, just refernce it as you would an actual field:
[MetadataType(typeof(MyClassMetadata))]
public partial class MyClass
{
[ScaffoldColumn(true)]
public string CustomString
{
return "foo";
}
}
public class MyClassMetadata
{
[Display(Name = "Custom")]
public object CustomString { get; set; }
}