I have a SimpleBeanEditorDriver to edit my account bean but i always get null values when i edit and call flush(). i checked everything, Google documentations, stackoverflow, google groups but didn't find any problem like. did i miss something ?
here is my View
public class AccountCreatorViewImpl extends Composite {
interface Driver extends SimpleBeanEditorDriver<Account, AccountEditor> {
}
interface AccountCreatorViewImplUiBinder extends UiBinder<HTMLPanel, AccountCreatorViewImpl> {
}
Driver driver = GWT.create(Driver.class);
private static AccountCreatorViewImplUiBinder ourUiBinder = GWT.create(AccountCreatorViewImplUiBinder.class);
private AccountCreatorPresenter presenter;
#UiField
AccountEditor accountEditor;
#UiField
Button create;
public AccountCreatorViewImpl() {
HTMLPanel rootElement = ourUiBinder.createAndBindUi(this);
initWidget(rootElement);
Account account = new Account();
driver.initialize(accountEditor);
driver.edit(account);
}
#UiHandler("create")
public void onCreate(ClickEvent event) {
Account editedAccount = driver.flush();
if (driver.hasErrors()) {
Window.alert("Has errors! ->"+driver.getErrors().toString());
}
Window.alert(editedAccount.getEmail() + "/" + editedAccount.getPassword());
// presenter.create(editedAccount);
}
}
and here is my simple editor
public class AccountEditor extends Composite implements Editor<Account> {
interface AccountEditorUiBinder extends UiBinder<HTMLPanel, AccountEditor> {
}
private static AccountEditorUiBinder ourUiBinder = GWT.create(AccountEditorUiBinder.class);
#UiField
TextBox email;
#UiField
PasswordTextBox password;
public AccountEditor() {
HTMLPanel rootElement = ourUiBinder.createAndBindUi(this);
initWidget(rootElement);
}
}
and this is my Account class
Account
public class Account implements Serializable {
private String email;
private String password;
public Account(String email) {
this.email = email;
}
public Account() {
}
public Account(String email, String password) {
this.email = email;
this.password = password;
}
public String getEmail() {
return email;
}
public String getPassword() {
return password;
}
}
i also have the same problem with another editor in my app. actually neither one works. when i press save or create i get null values of the entity.
Try adding setEmail() and setPassword() methods to your account class
Related
Say I have the below test case
I want to be able to bind camel case parameters:
anyData.put("my_id", "bob#gmail.com");
How can I get this test to pass??
public class FormBindingExampleTest {
public static class FormBindingExampleModel {
public String myid;
public String email;
public String getMyid() {
return myid;
}
public void setMyid(String myid) {
this.myid = myid;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
#Test
public void itShouldBindForm(){
Form<FormBindingExampleModel> userForm = form(FormBindingExampleModel.class);
Map<String,String> anyData = new HashMap();
anyData.put("my_id", "bob#gmail.com");
anyData.put("email", "secret");
FormBindingExampleModel user = userForm.bind(anyData).get();
System.out.println(user.myid);
assert(user.myid.equals("bob#gmail.com"));
}
}
Use form's fill() method inorder to populate the form with existing value.
#Test
public void itShouldBindForm(){
Form<FormBindingExampleModel> userForm = form(FormBindingExampleModel.class);
FormBindingExampleModel formModel = new FormBindingExampleModel();
formModel.setMyid("bob#gmail.com");
formModel.setEmail("secret");
userForm.fill(formModel);
FormBindingExampleModel user = userForm.get();
System.out.println(user.getMyid);
assert(user.getMyid.equals("bob#gmail.com"));
}
Documentation available here.
I am trying to understand how to correctly implement a LeafValueEditor for a non immutable object. Which of the two way is correct, or should something else be used?
public class Address {
public String line1;
public String city;
public String zip;
}
Option 1:
public class AddressEditor implements LeafValueEditor<Address>
{
private String line1;
private String city;
private String zip;
private Address address;
public void setValue(Address value)
{
this.line1 = value.line1;
this.city = value.city;
this.zip = value.zip;
this.address = value;
}
public Address getValue()
{
this.address.line1 = this.line1;
this.address.city = this.city;
this.address.zip = this.zip;
return this.address;
}
}
Option 2:
public class AddressEditor implements LeafValueEditor<Address>
{
private String line1;
private String city;
private String zip;
public void setValue(Address value)
{
this.line1 = value.line1;
this.city = value.city;
this.zip = value.zip;
}
public Address getValue()
{
Address a = new Address();
this.a.line1 = this.line1;
this.a.city = this.city;
this.a.zip = this.zip;
return a;
}
}
Probably neither, though both technically could work.
A LeafValueEditor is an Editor for leaf values - that is, values that don't generally contain other values. Usually a text or date or number field that would be visible on the page is the leaf editor, and those leaf nodes are contained in a normal Editor.
In this case, it could look something like this:
public class AddressEditor extends Composite implements Editor<Address> {
// not private, fields must be visible for the driver to manipulate them
// automatically, could be package-protected, protected, or public
protected TextBox line1;//automatically maps to getLine1()/setLine1(String)
protected TextBox city;
protected TextBox zip;
public AddressEditor() {
//TODO build the fields, attach them to some parent, and
// initWidget with them
}
}
See http://www.gwtproject.org/doc/latest/DevGuideUiEditors.html#Editor_contract for more details on how this all comes together automatically with just that little wiring.
I'm trying to add HATEOAS links to a JSON resource served by a Spring REST controller.
I see I should use a resource assembler as described at https://github.com/spring-projects/spring-hateoas
The example displays a Person class and a PersonResource class.
I understand the PersonResource class is defined as:
public class PersonResource extends ResourceSupport {
}
What is then the Person class ? Is it a data domain class ?
In my case, I have defined an Admin class that is a REST domain class, and I specified it as having resource support:
public class Admin extends ResourceSupport {
private String firstname;
private String lastname;
private String email;
private String login;
private String password;
private String passwordSalt;
public Admin() {
}
public String getFirstname() {
return this.firstname;
}
public void setFirstname(String firstname) {
this.firstname = firstname;
}
public String getLastname() {
return this.lastname;
}
public void setLastname(String lastname) {
this.lastname = lastname;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getLogin() {
return this.login;
}
public void setLogin(String login) {
this.login = login;
}
public String getPassword() {
return this.password;
}
public void setPassword(String password) {
this.password = password;
}
public String getPasswordSalt() {
return passwordSalt;
}
public void setPasswordSalt(String passwordSalt) {
this.passwordSalt = passwordSalt;
}
public EventAdmin toEventAdmin() {
EventAdmin eventAdmin = new EventAdmin();
BeanUtils.copyProperties(this, eventAdmin);
return eventAdmin;
}
public static Admin fromEventAdmin(EventAdmin eventAdmin) {
Admin admin = new Admin();
BeanUtils.copyProperties(eventAdmin, admin);
return admin;
}
}
My REST controller sees only this Admin class as it is a REST domain class. It does not know, and should not know, of anything data domain class.
So I wonder how to use the resource assembler support here.
I don't understand why I should have an additional data domain Admin class here.
kind Regards,
Following Mike's answer here is how my controller now looks like:
#RequestMapping(method = RequestMethod.POST, produces = "application/json; charset=utf-8")
#ResponseBody
public ResponseEntity<Admin> add(#RequestBody Admin admin, UriComponentsBuilder builder) {
AdminCreatedEvent adminCreatedEvent = adminService.add(new CreateAdminEvent(admin.toEventAdmin()));
HttpHeaders responseHeaders = new HttpHeaders();
responseHeaders.add("Content-Type", "application/json; charset=utf-8");
responseHeaders.setLocation(builder.path("/admin/{id}").buildAndExpand(adminCreatedEvent.getAdminId()).toUri());
Admin createdAdmin = adminResourceAssembler.toResource(adminCreatedEvent.getEventAdmin());
ResponseEntity<Admin> responseEntity = new ResponseEntity<Admin>(createdAdmin, responseHeaders, HttpStatus.CREATED);
return responseEntity;
}
Before, instead of using the resource assembler I was doing a:
Admin createdAdmin = Admin.fromEventAdmin(adminCreatedEvent.getEventAdmin());
createdAdmin.add(linkTo(methodOn(AdminController.class).add(createdAdmin, builder)).withSelfRel());
But it was not giving me the resource id in the url.
Your ResourceAssembler implementation needs to know about both the data domain class and the REST domain class, because its job is to convert the former to the latter.
If you want to keep knowledge of your data classes out of your controller, you could make a resource conversion service which would retrieve the data from the repo and use a ResourceAssembler to turn it into resources that the controller can know about.
#Component
public class AdminResourceAssembler extends ResourceAssemblerSupport<Admin, AdminResource> {
public AdminResourceAssembler() {
super(AdminController.class, AdminResource.class);
}
public AdminResource toResource(Admin admin) {
AdminResource adminResource = createResourceWithId(admin.getId(), admin); // adds a "self" link
// TODO: copy properties from admin to adminResource
return adminResource;
}
}
#Service
public class AdminResourceService {
#Inject private AdminRepository adminRepository;
#Inject private AdminResourceAssembler adminResourceAssembler;
#Transactional
public AdminResource findOne(Long adminId) {
Admin admin = adminRepository.findOne(adminId);
AdminResource adminResource = adminResourceAssembler.toResource(admin);
return adminResource;
}
}
#Controller
#RequestMapping("/admins")
public class AdminController {
#Inject private AdminResourceService adminResourceService;
#RequestMapping(value="/{adminId}", method=RequestMethod.GET)
public HttpEntity<AdminResource> findOne(#PathVariable("adminId") Long adminId) {
AdminResource adminResource = adminResourceService.findOne(adminId);
return new ReponseEntity<>(adminResource, HttpStatus.OK);
}
}
I am having issues with RPC calls and GWT. Essentially, I have a Person class (common code between client and server) that is created in the client side web code, sent to the server code via an RPC call, and then saved to a DB (OrientDB). I have verified that the following work:
RPC call - I am able to send info to the server and retrieve info from the server
save to DB - have verified that a Person object is saved to the DB
Where I am having issues is the transfer of the POJO from the client to the server. I have verified that the POJO's properties are intact right before it is sent to the server, however, the object passed to the server contains null values for all properties. Essentially, the class is transferred but the information is not. It then saves to the DB, but obviously without any relevant information contained within it.
I will copy what I feel is relevant below, please let me know what else I can provide to make this problem easier to identify. Note these are still in a testing state, so mind the comments :)
Any idea why my POJO's information is being lost in translation?
Person object, followed by the abstract class it inherits from:
public class Person extends org.matesweb.shared.AbsPerson implements Serializable
{
#Id
private String id; // DON'T CREATE GETTER/SETTER FOR IT TO PREVENT THE CHANGING BY THE USER APPLICATION,
// UNLESS IT'S NEEDED
//sets new user details
public void setPerson(String fIrstName, String mIdInit, String lAstName, String email, String password)
{
firstName = fIrstName;
middleInitial = mIdInit;
lastName = lAstName;
}
/*getter and setter methods - required for every
* field due to restrictions imposed by OrientDB*/
public Object getId()
{
String tmp;
tmp = id.toString();
return tmp;
}
//end class
}
public class AbsPerson implements Serializable
{
String firstName;
String middleInitial;
String lastName;
// public sys.Login login;
public org.matesweb.shared.Group[] groups;
private org.matesweb.shared.Purchase[] purchases;
/*this method adds a new purchase to the purchases variable*/
/* public void addPurchase(float price, String description)
{
people.Purchase newPurchase = new people.Purchase(login, price, description);
}
*/
/*adds a person to a group by comparing the passed in group ID and PWD*/
public void addGroup(String groupID, String groupPWD)
{
//compare group ID with group PWD to add a user to the group
}
/*getter and setter methods - required for every
* field due to restrictions imposed by OrientDB*/
public String getFirstName()
{
return firstName;
}
public void setFirstName(String name)
{
firstName = name;
}
public String getMiddleInitial()
{
return middleInitial;
}
public void setMiddleInitial(String midInit)
{
middleInitial = midInit;
}
public String getLastName()
{
return lastName;
}
public void setLastName(String ln)
{
lastName = ln;
}
/*
public sys.Login getLogin()
{
return login;
}
public void setLogin(sys.Login log)
{
login = log;
}
*/
public org.matesweb.shared.Group[] getGroups()
{
return groups;
}
public void setGroups(org.matesweb.shared.Group[] gro)
{
groups = gro;
}
public org.matesweb.shared.Purchase[] getPurchases()
{
return purchases;
}
public void setPurchases(org.matesweb.shared.Purchase[] purch)
{
purchases = purch;
}
}
Service
package org.matesweb.client;
import com.google.gwt.user.client.rpc.RemoteService;
import com.google.gwt.user.client.rpc.RemoteServiceRelativePath;
import org.matesweb.shared.Person;
#RemoteServiceRelativePath("peopleService")
public interface PeopleService extends RemoteService {
//test services
String stringTest(String outgoingString);
Person getPerson(String persId);
//production services
String savePerson(Person p);
}
ServiceAsync
import com.google.gwt.user.client.rpc.AsyncCallback;
import org.matesweb.shared.Person;
public interface PeopleServiceAsync
{
//tests
void stringTest(String outgoingString, AsyncCallback<String> incomingString);
void getPerson(String persId, AsyncCallback<Person> retPerson);
//production services
void savePerson(Person p , AsyncCallback<String> st);
}
ServiceImpl call for this particular method:
//production calls
#Override
public String savePerson(Person p) {
String st = ioObj.saveObj(p);
if(st.equals("Success")){
return "Your information has been saved successfully!";
} else{
return "Something has gone wrong on our end... Sorry! Error:<br /> " + st;
}
}
and finally, the call itself
private static void savePerson(Person p)
{
// Initialize the service proxy.
if (peopleSvc == null) {
peopleSvc = GWT.create(PeopleService.class);
}
//resets status
st="";
// Set up the callback object.
AsyncCallback<String> callback = new AsyncCallback<String>() {
#Override
public void onFailure(Throwable caught) {
st = caught.getMessage();
Label stLabel= new Label(st);
personTable.setWidget(3,1,stLabel);
}
#Override
public void onSuccess(String result) {
st = result;
HTML stLabel= new HTML(st);
joinPanel.add(stLabel);
}
};
// Make the call to the people service.
peopleSvc.savePerson(p, callback);
}
I was able to fix this issue by implementing GWT's IsSerializable interface. I also removed the Serializable interface from the Person class and let it inherit IsSerializable from the abstract class it inherits from.
I have inherited some struts2 REST-plugin based code, and the following construct puzzles me:
#Namespace("/merchants/{id}")
public class MerchantAction extends ActionSupport implements ModelDriven<Object> {
private Merchant merchant = new Merchant(); // A Model
private Iterable<Merchant> merchants; // A list of models
....
public HttpHeaders index() {
merchants = merchantService.findAllMerchants();
return new DefaultHttpHeaders("index");
}
#Override
public Object getModel() {
return (merchant != null ? merchant : merchants);
}
public void setId(String id) {
merchant = merchantService.findMerchant(id));
}
In other words, it seems to be toggling between returning a list and returning an individual item in the getModel() call. Is this kosher ? Looks a bit strange to me
I've considered your approach, but finally gave it up. IMO, it lost the advantage of strong typed action.
My solution is, creating a ViewModel for each action. In the view models, there can be the single model, the list of the model, and other items for pages usage, such as items for drop down list or radio buttons.
So the UserViewModel is like:
public class UserViewModel implements IViewModel<User> {
private User model;
private List<User> list;
public void setModel(User user) {
this.model = user;
}
public User getModel() {
return model;
}
public void setList(List<User> list) {
this.list = list;
}
public List<User> getList() {
return list;
}
}
And the actions are like:
public class UserController implements ModelDriven<UserViewModel> {
private int id;
private UserViewModel model = new UserViewModel();
public String index() {
return "success";
}
public String show() {
return "success";
}
public void setId(int id) {
this.id = id;
}
public int getId() {
return this.id;
}
#Override
public UserViewModel getModel() {
return model;
}
}
But in this way, I still lose the shortcut way in jsp files. I should write long model.userName instead of short userName.
I'm still finding the best solution of it.