Imagine I've an action MyAction, with a field User with getters and setters.
Then I have two exposed public methods where I want to use visitor validation for the object User but with two different contexts, so that the User is validated in two different ways, depending on the method that has been called.
I want to do this with annotations only, no validation.xml.
See the example
public class MyAction extends ActionSupport {
private User user;
public User getUser() {
return this.user;
}
public void setUser(User user) {
this.user=user;
}
public string execute() {
//some code here ...
return SUCCESS;
}
#Validations(
visitorFields = {#VisitorFieldValidator(context="myContext1", fieldName="user", key="error.message", message="A default error message", shortCircuit=true)}
)
public string save() {
//some code here ...
return SUCCESS;
}
#Validations(
visitorFields = {#VisitorFieldValidator(context="myContext2", fieldName="user", key="error.message", message="A default error message", shortCircuit=true)}
)
public string update() {
//some code here ...
return SUCCESS;
}
//...
}
Now I'd like to specify the context (myContext1 and myContext2) into the annotations inside the User object, so that some validators fire when the save() method is called on MyAction while others fire when update() is called.
I imagine something like this:
public class User implements Serializable {
private Integer id;
private String name;
#RequiredFieldValidator(context="myContext2", message = "You must enter a value for data.")
public void setId(Integer id) {
this.id=id;
}
#RequiredFieldValidator(context="myContext1", message = "You must enter a value for data.")
public void setName(String name) {
this.name = name;
}
//some code... getters, etc...
}
I'd like to do this so that, for example, during creation operation (method save()) the name is required while during update operation (method update() ) the id is required. Unfortunately it seems to me that RequiredFieldValidator, so any other validator annotation in Struts2, does not support the "context" field.
I know that I can use a User-myContext1-validation.xml, and a User-myContext2-validation.xml file (I've not tried but I think I've understood it can be done) but I'd like to use annotations only.
Do you know How I can do this with annotations?
Related
I have a public POJO class whos constructor is protected & its setters are protected/private as well.
The only thing that is public is the getters.
public class RequestInfo {
private String user;
private String date;
private String action;
protected RequestInfo(String user, String date, String action) {
this.user = user;
this.date = date;
this.action = action;
}
public String getUser(){
return user;
}
...
...
private void setUser(String user){
this.user = user;
}
..
..
}
I want to write a JUnit test which tests a method, that gets as a parameter an instance of the POJO class I have mentioned in the beginning.
public String getReport(RequestInfo requestInfo){
String requestUser = requestInfo.getUser();
String requestDate = requestInfo.getDate();
String requestAction = requestInfo.getAction();
....
....
}
This complicates things for me, because I want to mock this instance in order to test the method as needed, but I can't mock it because:
I can't just create a new instance of the class and insert my mocked values because the constructor is protected.
#Test
public void getReportTest(){
RequestInfo requestInfo = new RequestInfo("john", "12DEC22", "addUser");
String report = ReportsManager.getReport(requestInfo);
assertEquals(.......)
.....
}
I can't mock it using Mockito.mock(RequestInfo.Class) because although it will create a mock of the class, but everything inside of it (fields) will be nulled, so the tested method, which relies on the info that the instance stores, will fail.
I can make the constructor public, but I wrote it as protected for a reason, and I don't want to break my design just because of one or two tests.
I have wrote the codes as an example to clarify my needs, please address to the general idea and not for these specific code samples
I'll be glad to get tips,
thanks.
So, while developing an app, I have to use event sourcing to track down all changes to model. The app itself is made using spring framework. The problem I encountered: for example, user A sends a command to delete an entity and it takes 1 second to complete this task. User B, at the same time, sends a request to modify, for example, an entity name and it takes 2 seconds to do so. So my program finishes deleting this entity (persisting an event that says this entity is deleted), and after it another event is persisted for the same entity, that says that we just modified its name. But no actions are allowed with deleted entities. Boom, we just broke the app logic. It seems to me, that I have to put methods that write to database in synchronized blocks, but is there are any other way to handle this issue? Like, I dunno, queuing events? The application is not huge, and not a lot of requests are expected, so users can wait for its request turn in the queue (of course I can return 202 HTTP Status Code to him, but like I said, requests are not resource heavy and there wont be a lot of them, so its unnecessary). So what is the best way for me to use here?
EDIT: Added code to illustrate the problem. Is using synchronized in this case is a good practice or there are other choices?
#RestController
#RequestMapping("/api/test")
public class TestController {
#Autowired
private TestCommandService testCommandService;
#RequestMapping(value = "/api/test/update", method = RequestMethod.POST)
#ResponseStatus(HttpStatus.OK)
public void update(TestUpdateCommand command) {
testCommandService.update(command);
}
#RequestMapping(value = "/api/test/delete", method = RequestMethod.POST)
#ResponseStatus(HttpStatus.OK)
public void delete(Long id) {
testCommandService.delete(id);
}
}
public class TestUpdateCommand {
private Long id;
private String name;
public TestUpdateCommand() {
}
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 interface TestCommandService {
void delete(Long id);
void update(TestRegisterCommand command);
}
#Service
public class TestCommandServiceImpl implements TestCommandService {
#Autowired
TestEventRepository testEventRepository;
#Override
#Transactional
public void delete(Long id) {
synchronized (TestEvent.class) {
//do logic, check if data is valid from the domain point of view. Logic is also in synchronized block
DeleteTestEvent event = new DeleteTestEvent();
event.setId(id);
testEventRepository.save(event);
}
}
#Override
#Transactional
public void update(TestUpdateCommand command) {
synchronized (TestEvent.class) {
//do logic, check if data is valid from the domain point of view. Logic is also in synchronized block
UpdateTestEvent event = new DeleteTestEvent();
event.setId(command.getId());
event.setName(command.getName());
testEventRepository.save(event);
}
}
}
#Entity
public abstract class TestEvent {
#Id
private Long id;
public Event() {
}
public Event(Long id) {
this.id = id;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
}
#Entity
public class DeleteTestEvent extends TestEvent {
}
#Entity
public class UpdateTestEvent extends TestEvent {
private String name;
public UpdateTestEvent() {
}
public UpdateTestEvent(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public interface TestEventRepository extends JpaRepository<TestEvent, Long>{
}
Make sure you read Don't Delete -- Just Don't by Udi Dahan.
I have to put methods that write to database in synchronized blocks, but is there are any other way to handle this issue?
Yes, but you have to be careful about identifying what the issue is...
In the simple version; as you have discovered, allowing multiple sources of "truth" can introduce a conflict. Synchronization blocks is one answer, but scaling synchronization is challenging.
Another approach is to use a "compare and swap approach" -- each of your writers loads the "current" copy of the state, calculates changes, and then swaps the new state for the "current" state. Imagine two writers, one trying to change state:A to state:B, and one trying to change state:A to state:C. If the first save wins the race, then the second save fails, because (A->C) isn't a legal write when the current state is B. The second writer needs to start over.
(If you are familiar with "conditional PUT" from HTTP, this is the same idea).
At a more advanced level, the requirement that the behavior of your system depends on the order that messages arrive is suspicious: see Udi Dahan's Race Conditions Don't Exist. Why is it wrong to change something after deleting it?
You might be interested in Martin Kleppmann's work on conflict resolution for eventual consistency. He specifically discusses examples where one writer edits an element that another writer deletes.
Believing and using Which #NotNull Java annotation should I use?, I have a class which has certain fields marked as #NotNull [package javax.validation.constraints] to pass on to the clients. The class also implement the default getter and setter for such fields. Sample class below -
public class MyClass
{
public MyClass() {
}
#NotNull
private String name;
private Boolean bool;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Boolean isBool() {
return bool;
}
public void setBool(Boolean bool) {
this.bool = bool;
}
}
I am left a little puzzled up with the usage of the getter as follows in the business logic -
if(new MyClass().getName() !=null) {
//do something
}
Is this null check not redundant, (if not) curious to know WHY?
Also if its redundant, would like to give a thought of setting a null value and getting the value of the param. Gave this a try as -
void test() {
myClass.setName(null);
if (myClass.getName() == null) {
System.out.println("It should not be null"); // this got printed
}
}
#NonNull is only a hint for your tooling, it does not affect how the java language itself handles nulls. It also requires every interaction to be properly annotated to ensure all mistakes are found.
This happens in your case, while the name field is annotated the methods interacting with that field are not, so the tooling cannot make any assumptions about those methods and their nullability.
However if you introduce more annotations like this:
public void setName(#Nullable String name) {
this.name = name; // should now have a warning
}
#NonNull
public String getName() {
return name;
}
Now the tooling should indicate new MyClass().getName() != null as always true. It also warns in setName that you're setting a nullable value to a non-null property and that is probably wrong.
The way that is fixed:
public void setName(#NonNull String name) {
// setName(null) would cause a warning
// Also add an exception if the annotation is ignored.
this.name = Objects.requireNonNull(name);
}
/* or */
public void setName(#Nullable String name) {
if (name == null) return; // Guard against setting null
this.name = name;
}
I have the following class structure
public Abstract class Person {
private String fullName;
private Address address;
private Phone ;
}
class Staff extends Person{
private String staffId;
}
I want to apply validation using JSR-303 on class Staff whereby Staff address and phone cannot have the value of null. However, I have some other classes that are class of Person where I don't wish to have the validation to be applied.
One way to do this that I could think of is by refactor Person and push the fields 'address' and 'phone' to Staff, but this means refactoring a lot of other classes (and not to mention redundancy this shall cause), and hence something I want to avoid.
Update.
I have changed Staff class, as follows
public class Staff extends Person {
#NotNull
private String staffEmploymentId;
public String getStaffEmploymentId() {
return staffEmploymentId;
}
public void setStaffEmploymentId(String id) {
this.staffEmploymentId = id;
}
#Override
#NotNull
public void setPhones(List<Phone> phones) {
super.phones = phones;
}
#Override
#NotNull
public void setAddress(Address a) {
super.address = a;
}
#Override
#NotNull
public Address getAddress(){
return super.address;
}
}
However, I've got the following error.
javax.validation.ValidationException: Property setAddress does not follow javabean conventions.
I am using Apache BVal, as opposed to Hibernate Validator.
Annotate getters instead of fields using annotations from JSR-330.
You can override getters in Stuff and annotate them.
Let's assume I have this class :
#EntityListeners({MyListener.class})
class MyClass {
String name;
String surname;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSurname() {
return name;
}
public void setSurname(String name) {
this.name = name;
}
public void save() {
JPA.em().persist(this);
return this;
}
public void update() {
JPA.em().merge(this);
}
public static MyClass findById(Long id) {
return JPA.em().find(MyClass.class, id);
}
}
Now in my MyListener class I'm trying to figure out the previous value MyClass instance versus the new value that is about to get saved(updated) to database. I do this with preupdate metdhod :
#PreUpdate
public void preUpdate(Object entity) {
...some logic here...unable to get the old object value in here
}
So assuming I have a MyClass objects instance with name and surname :
MyClass mycls = new MyClass();
mycls.setName("Bob");
mycls.setSurname("Dylan");
mycls.save();
This wasn't picked up by listener which is ok because I'm listening only to updates.
Now if I were to update this instance like so :
MyClass cls = MyClass.findById(someLongId)
cls.setSurname("Marley");
cls.update();
So this triggers the preUpdate method in mylistener and when I try to :
MyClass.findById(someLongId);
When I debug I already get the newly updated instance but the update hasn't happened yet because when I check in database in column surname it's still Dylan.
How do I get the value from database in my preUpdate method and not the one I just updated?
I think an easy way is to save the previous value in a transient variable that JPA will not persist.
So just introduce a variable previousSurname and save the actual value before you overwrite it in the setter.
If you want to save multiple properties it would be easy if your class MyClass is Serializable.
If so add a post load listener
public class MyClass implements Serializable {
#Transient
private transient MyClass savedState;
#PostLoad
private void saveState(){
this.savedState = SerializationUtils.clone(this); // from apache commons-lang
}
}
But be aware that the savedState is a detached instance.
You can then access the previous state in your EntityListener.
You can also move the PostLoad listener to the EntityListener class. But then you need access to the savedState field. I recommend to make it either package scoped or use a package scoped accessor and put MyClass and MyListener in the same package,
public class MyListener {
#PostLoad
private void saveState(MyClass myClass){
myClass.saveState(SerializationUtils.clone(myClass)); // from apache commons-lang
}
}
public class MyClass implements Serializable {
#Transient
private transient MyClass savedState;
void saveState(MyClass savedState){
this.savedState = savedState;
}
}