I have a Java Object with many other nested Objects and lists of Objects. When the request arrives from the client, I see that the Object is populated only to a few levels. Is there any configuration that sets this is Struts 2? Here is my example.
class MyActionClass extends ActionSupport {
private Abc abc;
public Abc getAbc() {
return abc;
}
public void setAbc(Abc abc) {
this.abc = abc;
}
public String populate() {
MyService myService = new MyService();
abc = myService.getMyAbc();
return SUCCESS;
}
public String update() {
MyService myService = new MyService();
myService.updateAbc(abc);
return SUCCESS;
}
}
class Abc {
private List<Def> defList;
private Ghi ghi;
public void setDefList(List<Def> defList) {
this.defList = defList;
}
public List<Def> getDefList(){
return defList;
}
public void setGhi(Ghi ghi) {
this.ghi = ghi;
}
public Ghi getGhi() {
return ghi;
}
}
class Def {
private String name;
private long id;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
}
class Ghi {
private List<Def> defList;
private String ghiName;
public void setDefList(List<Def> defList) {
this.defList = defList;
}
public List<Def> getDefList() {
return defList;
}
public void setGhiName(String ghiName) {
this.ghiName = ghiName;
}
public String getGhiName() {
return ghiName;
}
}
When I call the populate method and when send to the jsp, the iteration happens good with all the elements. But, when I try to update, i.e. when then form is submitted, the update() method is called, but the instance variable abc does not get populated completely.
I have seen the url which is passed and everything seems to be fine. Let me tell you what happens. The url will be something like (splitting with line break for easy understanding here),
&abc.defList[0].name=alex
&abc.defList[0].id=1
&abc.defList[1].name=bobby
&abc.defList[1].id=2
&abc.ghi.ghiName=GHINAME
&abc.ghi.defList[0].name=Jack
&abc.ghi.defList[0].id=1
&abc.ghi.defList[1].name=Jill
&abc.ghi.defList[1].id=2
In this case, the defList inside abc and ghi.ghiName in abc are populated with no issues. But the defList of abc.ghi is not populated. Is this a common behavior of Struts 2? Is ther any means by which this can be overridden?
Got the issue solved. Struts 2 rock. Since the code I got was for a bug fix, did not know what was inside it, not even checked it once.
The culprit was the toString() method which was overridden. This had no check on the map for null and called the entrySet() method on it. This generated Exception and prevented Struts from populating the objects.
For better understanding, Struts do call the toString() method for some purpose while populating. If anyone faces this in future, do remember to check if you have overridden toString() and if everything is set inside it.
Related
I have pojo class Ticket
public class Ticket implements Serializable{
#JsonProperty("lineItemStatus")
private String revisionStatus;
public String getRevisionStatus() {
return revisionStatus;
}
public void setRevisionStatus(String revisionStatus) {
this.revisionStatus = revisionStatus;
}
public void setRevisionStatus(RevisionStatus revisionStatus) {
String status = "";
if (revisionStatus != null) {
switch (revisionStatus) {
case added: {
status = "New";
break;
}
case updated: {
status = "Modified";
break;
}
}
}
this.revisionStatus = status;
}
}
Also I have an enum
public enum RevisionStatus {
added {
#Override
public String getName() {
return this.name();
}
},
updated {
#Override
public String getName() {
return this.name();
}
}
public abstract String getName();
}
During GET request , I use setRevisionStatus(RevisionStatus revisionStatus) method and i get response like for example
{"lineItemStatus": "Modified"} which is fine
But problem occurs during PUT request . During PUT request, my requirement is that I should be able to send payloads like for {"lineItemStatus": "Modified"} or {"lineItemStatus": "New"} or {"lineItemStatus": "abc"} , meaning lineItemStatus should be able to accept any String value . I am using #RequestBody Ticket ticket for receiving the payload.
The debugger doesn't come inside the controller and fails at the payload step . How do I handle this error without making any changes inside Enum ?
You can do it by updating your enum:
public enum RevisionStatus {
added("New") {
#Override
public String getName() {
return this.name();
}
},
updated("Modified") {
#Override
public String getName() {
return this.name();
}
};
private String status;
private RevisionStatus(String status) {
this.status = status;
}
public abstract String getName();
/**
* #return the status
*/
public String getStatus() {
return status;
}
#JsonCreator
public static RevisionStatus fromValue(String text) {
if(StringUtils.isNoneBlank(text)) {
for (RevisionStatus b : RevisionStatus.values()) {
if (String.valueOf(b.toString()).equalsIgnoreCase(text.trim())) {
return b;
}
}
}
return null;
}
}
Here we have updated enum to value enum. And fromValue() method with #JsonCreator annotation will bind this String value with the Enum constant.
Additionally this way you won't need that switch cases during get method. As getStatus() method will give you the status value directly. And that will improve your code design also.
Just an additional point here, I don't see any need of this getName() method, as the placed where getName() is called, directly name() can be called. As that is also a public method.
I am completely new to Java... :(
I need to pass a variable from a parent class to a child class, but I don't know how to do that.
The variable is located in a method in the parent class and I want to use it in one of the methods of the child class.
How is this done?
public class CSVData {
private static final String FILE_PATH="D:\\eclipse\\250.csv";
#Test
public static void main() throws IOException {
//some code here
String firstname1 = array.get(2).get(1);
}
}
and then the other class
public class UserClassExperimental3 extends CSVData {
public static void userSignup() throws InterruptedException {
//some code here
String firstname= firstname1; //and here it doesnt work
}
}
Actually I think I succeeded doing that this way:
added the variable here:
public static void userSignup(String firstname1)
then used it here:
String firstname=firstname1;
System.out.println(firstname);
But now I can't pass it to the method that needs it.
The variable firstname1 is a local variable. You can't access it outside its scope - the method.
What you can do is pass a copy of the reference to your subclass.
Since you're calling a static method, the easiest way is to pass the reference as an argument to the method call:
#Test
public static void main() throws IOException {
//some code here
String firstname1 = array.get(2).get(1);
UserClassExperimental3.userSignup( firstName1 );
}
public class UserClassExperimental3 extends CSVData {
public static void userSignup( String firstNameArg ) throws InterruptedException {
//some code here
String firstname = firstnameArg; // Now it works
}
}
That said, since you're using inheritance, you might find it useful to use an instance method. Remove "static" from the method. In main(), construct an instance of the class, provide it the name, and call the method on the instance.
#Test
public static void main() throws IOException {
//some code here
String firstname1 = array.get(2).get(1);
UserClassExperimental3 instance = new UserClassExperimental3( firstName1 );
instance.userSignup();
}
public class UserClassExperimental3 extends CSVData {
private String m_firstName;
public UserClassExperimental3( String firstName ) {
m_firstName = firstName;
}
public void userSignup() throws InterruptedException {
//some code here
String firstname = m_firstname; // Now it works
}
}
If you also add userSignup() to the CSVData class, you can refer to the specific subclass only on creation. This makes it easier to switch the implementation, and it makes it easier to write code that works regardless of which subclass you're using.
String firstname1 = array.get(2).get(1);
CSVData instance = new UserClassExperimental3( firstName1 );
instance.userSignup();
public class Main {
public static void main(String[] args) {
User user=new User();
user.setId(1);
user.setName("user");
user.setEmail("user#email.com");
user.save();
}
}
public class User extends Model {
private int id;
private String name;
private String email;
public int getId() {
return id;
}
public void setId(int 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;
}
}
import java.lang.reflect.Field;
public class Model {
public void save(){
for(Field field: Model.this.getClass().getDeclaredFields()) {
field.setAccessible(true);
try {
System.out.println(field.getName()+"="+field.get(Model.this));
} catch (Exception ex) {
ex.printStackTrace();
}
}
return;
}
}
I have two classes: one called Student and the other one called Course. I would like to make a simulation for a simple registration system.
My Student class part has the following form:
class Student
{
private String id,
private Course[] listOfCourses;
private int numCourse;
//accesing methods
public registration(Course course){
listOfCourses[numCourse]=course;
numCourse++;
}
public Course[] getCourse(){
return listOfCourses;
}
}
and the Course class has the following form:
class Course
{
String id, String courseName;
//constructor
//accesing methods
}
I would like that by pressing a buttom in a form made in Java Swing, to display the contents of the courses registered by one specific student into a jTable. I have tried the following, but with no results at all:
Student e=new Student();
Course d[]=new Course[4];
d=e.getCourses(); //to receive the array of Courses from the Student class
for (int i=0;i<d.length;i++){
jTable2.setValueAt(estLista[i].getName(), i, 0);
}
how I can do that? I mean there is a way in which I could get the contents of the array, that is stored in the Course class, into the ActionEvent of the button?
From the code you have provided I believe there atleast one reason why you are not getting the courses.. because it is not set in registration process:) (Also the syntax is not correct unless you have a registration class?) This might not be a complete solution but it corrects one of the problem
public void registration(Course course){
// listOfCourses[numCourse];
listOfCourses[numCourse]=course;
numCourse++;
}
Ok, it is not too clear for me yet, but I will put some code and tell me if it helps you.
Note: Not tested
For Student (sorry I prefer to use lists instead of arrays):
public class Student {
private String id;
private List<Course> takenCourses;
public void registration(Course course){
if (this.takenCourses != null) {
takenCourses.add(course);
} else {
System.err.println("an array has not been specified.");
}
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public List<Course> getTakenCourses() {
return takenCourses;
}
public void setTakenCourses(List<Course> takenCourses) {
this.takenCourses = takenCourses;
}
For course:
public class Course {
private String id;
private String name;
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;
}
For your UI, I just created a "simulation" of UI, I assume you have implemented something more complete... I assume you have intialized the components as global variables for your frame or panel or at least you have methods to get them.
public class UIHelper extends JFrame {
Student student = new Student();
JButton btnAction;
JTable myTable;
public UIHelper() {
//Methods for creating UI
//.
//.
//.
student.setId("stackoverflowed");
student.setTakenCourses(new ArrayList<Course>());
btnAction = new JButton("Action!");
//Methods of the JButton (...)
btnAction.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
//Now just process since student is a global variable (you can set it static as well) but it shouldn't be a good practice at all
for (Course course : student.getTakenCourses()) {
System.out.println(course.getName());
//Add the element to your table.
}
}
});
}
public static void main(String[] args) {
//Assume this is your UI
new UIHelper();
}
Hope I give you an idea, best regards.
I have a class called Property which has nothing but get-methods. All the fields will be set when a new instance of Propertyis created. Property implements an interface called IProperty.
Due to some bug in a library I use, I have to set the name of an instance of Property anew after its creation. Therefore it was suggested to create a WrapperPropertyclass that will provide a public setName-method which itself calls a therefore created setName()-method in Property, which will be protected/package view.
The problem is that I cannot make this method protected in Property, because Eclipse tells me to add it to the interface IProperty and make it public.
Is there some work-around to it?
WrapperIProperty:
public class WrapperIProperty {
private IProperty prop;
WrapperIProperty(Property prop) {
this.prop = prop;
}
public void setName(String name) {
prop.setName(name);
}
}
Property:
public class Property implements IProperty {
String name;
protected void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public int getFoobar() {
return 123;
}
public int getWhatever() {
return 987;
}
}
IProperty:
public interface IProperty {
public int getWhatever();
public int getFoobar();
public String getName();
}
This is how it looks at the moment. Obviously it won't work, since I cannot let the method be protected in the Property class. Therefore I best get rid of the interfacee entry somehow. But how?
What you probably want to do is to leave the IProperty interface alone (don't add the setName method to it) and create a delegating wrapper class which provides the method you want (wraps an implementation of the interface).
This way you can feed wrapped properties and regular properties to whatever needs them.
public class WrappedProperty implements IProperty {
private String name;
private Property prop;
WrappedProperty (Property prop) {
this.prop = prop;
}
protected void setName(String name) {
this.name = name;
}
public int getWhatever() {
return prop.getWhatever();
}
public int getFoobar() {
return prop.getFoobar();
}
public String getName() {
if (this.name == null) {
return prop.getName():
} else {
return this.name;
}
}
}
public class Property implements IProperty {
public String getName() {
return "blah";
}
public int getFoobar() {
return 123;
}
public int getWhatever() {
return 987;
}
}
public interface IProperty {
public int getWhatever();
public int getFoobar();
public String getName();
}
Methods in an Interface are public in scope so implementing class cannot override methods by reducing their accessibility. Make them public
You cannot have a public methodName in an Interface and a private or protected methodName in a Class implementing this Interface.
So you can have the methodName public in your Class :
this method do nothing
this method call [another]methodNameProtected (you give another name to a new protected method)
UPDATE
If you want it only in Interface you have to change your Interface in an AbstractClass and put in it the method
public final returnCode methodName if the method is common for all inherited classes
Found the solution to that problem:
WrapperIProperty :
public class WrapperIProperty {
private Property prop;
public WrapperIProperty(IProperty prop) {
this.prop = (Property) prop;
}
public void setName(String name) {
prop.setName(name);
}
}
Property:
public class Property implements IProperty {
private String name = null;
[...]
void setName(String name) {
this.name = name;
}
}
IProperty:
public interface IProperty {
[...]
}
This will do the job
I have a question concerning Json deserialization using Jackson.
I would like to deserialize a Json file using a class like this one:
(taken from http://wiki.fasterxml.com/JacksonInFiveMinutes)
public class User
{
public enum Gender { MALE, FEMALE };
public static class Name {
private String _first, _last;
public String getFirst() { return _first; }
public String getLast() { return _last; }
public void setFirst(String s) { _first = s; }
public void setLast(String s) { _last = s; }
}
private Gender _gender;
private Name _name;
private boolean _isVerified;
private byte[] _userImage;
public Name getName() { return _name; }
public boolean isVerified() { return _isVerified; }
public Gender getGender() { return _gender; }
public byte[] getUserImage() { return _userImage; }
public void setName(Name n) { _name = n; }
public void setVerified(boolean b) { _isVerified = b; }
public void setGender(Gender g) { _gender = g; }
public void setUserImage(byte[] b) { _userImage = b; }
}
A Json file can be deserialized using the so called "Full Data Binding" in this way:
ObjectMapper mapper = new ObjectMapper();
User user = mapper.readValue(new File("user.json"), User.class);
My problem is the usage of the inner class "Name". I would like to do the same thing without using inner classes. The "User" class would became like that:
import Name;
import Gender;
public class User
{
private Gender _gender;
private Name _name;
private boolean _isVerified;
private byte[] _userImage;
public Name getName() { return _name; }
public boolean isVerified() { return _isVerified; }
public Gender getGender() { return _gender; }
public byte[] getUserImage() { return _userImage; }
public void setName(Name n) { _name = n; }
public void setVerified(boolean b) { _isVerified = b; }
public void setGender(Gender g) { _gender = g; }
public void setUserImage(byte[] b) { _userImage = b; }
}
This means to find a way to specify to the mapper all the required classes in order to perform the deserialization.
Is this possible? I looked at the documentation but I cannot find any solution.
My need comes from the fact that I use the Javassist library to create such classes, and it does not support inner or anonymous classes.
Thank you in advance
There should be no difference between the static inner class Name, and the top-level class of the same name. The Jackson runtime should not be able to meaningfully distinguish between the two situations.
Have you tried moving the Name class out of User, changing it into a top-level class? It should still work as before.
edit: I just tried this, and it works fine when Name is a top-level class. The example had it as an inner class for the sake of brevity, I suspect.
mr. Skaffman's answer is right on. The only additional thing to mention is that unlike JAXB, Jackson does not generally require you to specify classes you operate on, except for the root class (and not always even that, if you use Polymorphic Handling).