Spring JDO - makePersistent not returning created object - spring

I'm using Spring and JDO connecting to a MySQL database.
When I persist an object, I am expecting to see the created object returned by the makePersistent() method. It does return an object, but this object only has the ID of the newly created object. All the other fields that were persisted now have a value of null.
In the code example below, I insert a value of 12 with the carouselNumber. The returned object has that value set to NULL and the id has the newly created ID value from the database.
I've used JDOHelper.getObjectState() and found that my object is in a Transient state.
I'm wondering if there is some annotation that I am missing to tell JDO to return all the values on the object, rather than just the newly generated ID.
EDIT:
I've done some further exploring and found that when I use the raw Datanucleus JDP API that thsi works fine. The problem only seems to be when I use Spring's JDO template. I'd really like to get an understanding of why this differs. Thanks
Thanks in Advance,
Brian.
#PersistenceCapable(table = "CAROUSEL", identityType = IdentityType.APPLICATION)
public class Carousel {
#PrimaryKey(column = "ID")
#Persistent(valueStrategy = IdGeneratorStrategy.INCREMENT)
private Long id;
#Column(name = "CAROUSEL_NUM")
private int carourselNumber;
......
public class CarouselDAOImpl extends JdoDaoSupport implements ICarouselDAO {
public Carousel insert(Carousel carousel) {
return getJdoTemplate().makePersistent(carousel);
}
.....

The makePersistent method alters the carousel object you've passed in to generate an ID, so it doesn't need to return anything. Just make your method void and use the carousel you've passed in.

Related

Providing default values for validation in SpringBoot

I want SpringBoot to be able to provide default values for fields that the user must enter. For example, I have something like this:
*Controller class*
#PostMapping("/test")
public ResponseEntity<> myMethod(#RequestBody #Valid MyContract contract) {}
*MyContract class*
#Valid
DataObject dataObject;
*DataObject class*
#Component
public class DataObject {
private #Value("${field1.default}") String field1Default;
private String field1
public String getField1() {
return (field1 == null ? field1Default : field1);
}
}
The DataObject class needs to be created on a per request basis. There are also other places in the code where it needs to be created on demand. So I imagine it needs to be a Prototype object. But I can't figure out how to get Spring to created it properly when it creates it for the request.
Update
I have read more about #RequstBody, e.g., https://www.javadevjournal.com/spring/spring-request-response-body/ and Should spring #RequestBody class be singleton or prototype?, which explains that the object is not a Component, but a simple POJO that gets the values from the Json request. So it seems that there is no way to inject #Values from the Spring application.properties file. Is there any other way around this? Or another suggested implementation?

Spring Data Rest custom controller with patch method - how to merge resource with entity

By default when we have a repository with save method exposed we can do a PATCH request. Then Spring Data REST retrieves the original object from the database and apply changes to entity and then saves it for us (inside JsonPatchHandler class). This allows us to do the following request for class
class Address {
Long id;
String street;
Long houseNumber;
}
PATCH /api/addresses/1 with body
{ houseNumber: 123 }
And only this one field will be changed.
Now having custom controller we would like to in the update method receive the whole object (after HATEOAS merged it with the original object from the DB)
#RepositoryRestController
#ExposesResourceFor(Address.class)
#ResponseBody
#RequestMapping("/addresses")
public class AdddressController {
#PatchMapping("/{addressId}")
public Resource<Address> update(#RequestBody Resource<Address> addressResource, #PathVariable Long addressId) {
Address address= addressResource.getContent();
// .... some logic
address = addressRepository.save(address);
return new Resource<>(address);
}
}
Unfortunately in the place where I would do some logic I get the Address with null fields instead of the merged object.
Is it possible to plug the custom controller in the Spring Data REST stack so that when patching the request it will merge it for me (as it does for normal repositories)?
edit:
I would like to find a solution that works transparently both with PATCH(content-type:application/json-patch+json) and PATCH(content-type: application/hal+json)
After browsing the Spring sources I haven't found a reasonable solution. As a result I've created issue in their - JIRA
For the moment the only reasonable workaround is following - create custom controller that has PersitentEntityResource as a parameter and has both {id} and {repository} placeholders in its path i.e.
#PatchMapping("/addresses/{id}/{repository}")
public Resource<Address> update(PersistentEntityResource addressResource) {
...
}
which makes the invocation endpoint /addresses/123/addresses

#PathVariable Spring Controller

I'm working on a spring web application using thymeleaf as a view resolver lately, and when developping my controllers, i faced a new situation :
i'm not really sure about it but can the #Pathvariable passed from the view be an object ? (a compound key of a model to be precise ? )
i used ids before, but most of them were simple int ids, i just want to know if passing an object (which is the primary key of my object) is possible , and not simple int ids ?
And Thank you
You can use Spring PropertyEditor or Spring Converter see Spring Convertor
example
public class CategoryConverter implements Converter<String, Category>{
#Autowired
private CategoryService categoryService;
public Category convert(String id) {
return categoryService.findById(Long.valueOf(id));
}
}
But you may meet some problem when saving object directly to database.

spring security : Why can't we access Hibernate entitiy parameters in #PreAuthorize?

I have the following interface method on which I am applying #PreAuthorize :
#PreAuthorize("doSomething(#user.id)")
void something(User user, List<User> accessList);
where User is a Hibernate entity object. It gives me an error :
org.springframework.expression.spel.SpelEvaluationException:
EL1007E:(pos 13): Field or property 'id' cannot be found on null at
org.springframework.expression.spel.ast.PropertyOrFieldReference.readProperty(PropertyOrFieldReference.java:204)
There is no way that the user parameter is null, as if I remove the annotation, and inspect the value of user in the method that implements this interface method, there is a valid User object present there. Additionally, just before calling this method, I have made sure that the user object is correctly constructed.
I really can't figure out why would the user field be considered null by the SPEL parser
You can check with the debugger what's going on in MethodSecurityEvaluationContext, inside Object lookupVariable(String name) method:
#Override
public Object lookupVariable(String name) {
Object variable = super.lookupVariable(name);
if (variable != null) {
return variable;
}
if (!argumentsAdded) {
addArgumentsAsVariables();
argumentsAdded = true;
}
and so you can see what's really going on in the addArgumentsAsVariables() method as the convertion of method arguments to SPEL variables is implemented very clearly in Spring.
Spring Security has a better answer for this problem now:
http://docs.spring.io/spring-security/site/docs/3.2.5.RELEASE/reference/htmlsingle/#access-control-using-preauthorize-and-postauthorize
Basically, you can use the #P annotation or #Param annotation if you are using < JDK 8.
You can check LazyParamAwareEvaluationContext,inside loadArgsAsVariables() method, version 3.1.0.
The same key for different Entity, because of implementing interface.
I need to add something to this as the title indicates that we cannot access hibernate properties.
There are two editions of hasPermission, the loaded object and the serialized object. Here is some code from a test case:
#PreAuthorize("isAuthenticated() and hasPermission(#organization, 'edit')")
public long protectedMethod(Organization organization)
{
return organization.getId();
}
And for the latter here we see that we can infact access the id proprty of the organization (which is a hibernate entity):
#PreAuthorize("isAuthenticated() and hasPermission(#organization.getId(), 'organization', 'edit')")
public long protectedMethodSerializableEdtion(Organization organization)
{
return organization.getId();
}

Spring MVC 3.0: How do I bind to a persistent object

I'm working with Spring MVC and I'd like it to bind a a persistent object from the database, but I cannot figure out how I can set my code to make a call to the DB before binding. For example, I'm trying to update a "BenefitType" object to the database, however, I want it to get the object fromthe database, not create a new one so I do not have to update all the fields.
#RequestMapping("/save")
public String save(#ModelAttribute("item") BenefitType benefitType, BindingResult result)
{
...check for errors
...save, etc.
}
There are several options:
In the simpliest case when your object has only simple properties you can bind all its properties to the form fields (hidden if necessary), and get a fully bound object after submit. Complex properties also can be bound to the form fields using PropertyEditors.
You may also use session to store your object between GET and POST requests. Spring 3 faciliates this approach with #SessionAttributes annotation (from the Petclinic sample):
#Controller
#RequestMapping("/owners/*/pets/{petId}/edit")
#SessionAttributes("pet") // Specify attributes to be stored in the session
public class EditPetForm {
...
#InitBinder
public void setAllowedFields(WebDataBinder dataBinder) {
// Disallow binding of sensitive fields - user can't override
// values from the session
dataBinder.setDisallowedFields("id");
}
#RequestMapping(method = RequestMethod.GET)
public String setupForm(#PathVariable("petId") int petId, Model model) {
Pet pet = this.clinic.loadPet(petId);
model.addAttribute("pet", pet); // Put attribute into session
return "pets/form";
}
#RequestMapping(method = { RequestMethod.PUT, RequestMethod.POST })
public String processSubmit(#ModelAttribute("pet") Pet pet,
BindingResult result, SessionStatus status) {
new PetValidator().validate(pet, result);
if (result.hasErrors()) {
return "pets/form";
} else {
this.clinic.storePet(pet);
// Clean the session attribute after successful submit
status.setComplete();
return "redirect:/owners/" + pet.getOwner().getId();
}
}
}
However this approach may cause problems if several instances of the form are open simultaneously in the same session.
So, the most reliable approach for the complex cases is to create a separate object for storing form fields and merge changes from that object into persistent object manually.
So I ended up resolving this by annotating a method with a #ModelAttribute of the same name in the class. Spring builds the model first before executing the request mapping:
#ModelAttribute("item")
BenefitType getBenefitType(#RequestParam("id") String id) {
// return benefit type
}
While it is possible that your domain model is so simple that you can bind UI objects directly to data model objects, it is more likely that this is not so, in which case I would highly recommend you design a class specifically for form binding, then translate between it and domain objects in your controller.
I'm a little confused. I think you're actually talking about an update workflow?
You need two #RequestMappings, one for GET and one for POST:
#RequestMapping(value="/update/{id}", method=RequestMethod.GET)
public String getSave(ModelMap model, #PathVariable Long id)
{
model.putAttribute("item", benefitDao.findById(id));
return "view";
}
then on the POST actually update the field.
In you example above, your #ModelAttribute should already be populated with a method like the above method, and the properties be bound using something like JSTL or Spring tabglibs in conjunction with the form backing object.
You may also want to look at InitBinder depending on your use case.

Resources