Is class casting allowed? - oop

I have 2 public classes; Person and Engineer. Engineer is inherited from Person class.
Now in main() I have a person object say
Person abc = new Person();
and I am trying to convert "abc" to Engineer i.e.
Engineer xyz = (Engineer) abc;
Question: Is this legal? My understanding is I cannot do it because "abc" might have different attributes.
Code:
public class Person {
private String firstname;
private String lastname;
private String gender;
public Person(String first, String last, String gen) {
firstname = first;
lastname = last;
gender = gen;
}
public void setFirstName(String name) {
firstname = name;
}
public void setLastName(String name) {
lastname = name;
}
public void setGender(String gen) {
gender = gen;
}
public String getFirstName() {
return firstname;
}
public String getLastName() {
return lastname;
}
public String getGender() {
return gender;
}
public toString() {
return "firstname=" + firstname + "lastname=" + lastname + "gender=" + gender;
}
public class SoftwareEngineer extends Person {
public String teamname;
public String bestlanguage;
public SoftwareEngineer(String first, String last, String gen, String team, String lang) {
firstname = first;
lastname = last;
gender = gen;
teamname = team;
bestlanguage = lang;
}
public toString() {
return "firstname=" + firstname + "lastname=" + lastname + "gender=" + gender + "teamname=" + teamname + "bestlanguage=" + bestlanguage;
}
public void main() {
SoftwareEngineer aaron = new SoftwareEngineer('Aaron','Gottlieb','M','IPSupport','SQL');
Person andy = new SoftwareEngineer('Andy','Gardner','M','IP','Java');
Person pete = new Person("Pete", "G", "M");
Person personAaron = aaron;
SoftwareEngineer sePete = (SoftwareEngineer) pete;
SoftwareEngineer seAndy = (SoftwareEngineer) andy;
pete.teamname = "FooBar";
aaron.setLastName("Brian");
}

Every engineer is a person, but not every person is an engineer. Now translate it to your OO domain. Do you think you can always cast Person to Engineer? I.e. assume that every person is an engineer?
No, but you can ask person: are you an engineer?:
if(abc instanceof Engineer) {
Engineer xyz = (Engineer) abc;
}
But you don't always have to know that. You can ask every person about name, it doesn't matter whether that person is an engineer or not:
Person p = new Engineer();
p.getFirstName();

Related

How to don't serialize the class field in FastJson?

Today I'm using FastJson(https://github.com/alibaba/fastjson), the following is my demo code.
class User {
private final String name;
private final int age;
private final String birthday;
private String password;
public User(String name, int age, String birthday) {
this.name = name;
this.age = age;
this.birthday = birthday;
}
public void setPassword(String pwd) {
this.password = pwd;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public String getBirthday() {
return birthday;
}
public String getPassword() {
return password;
}
#Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
", birthday='" + birthday + '\'' +
", password='" + password + '\'' +
'}';
}
}
It will serialize the field which has getXXX method. I do not want to serialize the password, and I will call the getPassword() to get the password value.
I do not want to rename the method getPassword and update the variable password to public.
Does anyone know how to ignore a field when serializing this class?
#JSONField(serialze=false)
public String getPassword() {
return password;
}

Spring RestController ignoring #jsonProperty/JsonGetter/JsonSetter

I am using Springboot 2.1.2.RELEASE. I have a get request with an object as input parameter. Expecting the attributes in my class to be request parameters. My EmployeeBean has properties in java naming convention. But I need the custom names to request parameters. Tried to achieve that using #JsonProperty/ #Jsongetter/ #JsonSetter annotations but its not working. Am I missing something?
#RequestMapping(value="/api", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE )
public List<Map<String, Object>> getEmployeeData(EmployeeBean employeeBean
#Data
public class EmployeeBean implements Serializable {
private static final long serialVersionUID = -2757478480787308113L;
#JsonProperty(value="first_name")
private String firstName;
#JsonProperty(value="last_name")
private String lastName;
Try this,
private String firstName;
private String lastName;
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
#JsonProperty(value="first_name")
public void setFirst_name(String firstName) {
this.firstName = firstName;
}
#JsonProperty(value="last_name")
public void setLast_name(String lastName) {
this.lastName = lastName;
}
controller
#RestController
public class JsonController {
#RequestMapping(value="/api", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE )
public List<Map<String, Object>> getEmployeeData(EmployeeBean employeeBean) {
System.out.println("employeeBean: "+employeeBean);
return null;
}
}
result:
employeeBean: EmployeeBean [firstName=firstName10, lastName=lastName20]
I've tested and it's worked
other options, using JsonCreator in constructor:
private String firstName;
private String lastName;
#JsonCreator
public EmployeeBean(#JsonProperty("first_name") String first_name, #JsonProperty("last_name") String last_name) {
this.firstName = first_name;
this.lastName = last_name;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}

JDBC/SQL - ID is always 0

so i'm trying to insert an hardcoded member to my Members table. I'm using Spring Boot & JDBC on Eclipse.
This is my schema.sql:
CREATE TABLE Members
(
ID int not null,
LastName varchar(255) not null,
FirstName varchar(255) not null,
PhoneNumber integer not null,
created timestamp not null,
primary key(ID)
);
INSERT INTO MEMBERS (ID, LASTNAME, FIRSTNAME,PHONENUMBER, CREATED)
VALUES(1001, 'Max', 'Mad', 0547547547, sysdate());
i got a findAll method in a DAO class:
public List<Member> findAll(){
return jtemp.query("select * from members", new BeanPropertyRowMapper<Member>(Member.class));
}
when i run it, it returns:
[Member [id=0, firstName=Mad, lastName=Max, phoneNumber=547547547, created=2017-10-31 18:57:21.606]]
As you can see the ID wasn't inserted for some reason.
my Member class is like this:
public class Member {
private long id;
private String firstName;
private String lastName;
private long phoneNumber;
private Date created;
public Member(long id, String firstName, String lastName, long phoneNumber, Date created) {
super();
this.id = id;
this.firstName = firstName;
this.lastName = lastName;
this.phoneNumber = phoneNumber;
this.created = created;
}
public long getUserId() {
return id;
}
public void setUserId(long userId) {
this.id = userId;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public long getPhoneNumber() {
return phoneNumber;
}
public void setPhoneNumber(long phoneNumber) {
this.phoneNumber = phoneNumber;
}
public Date getCreated() {
return created;
}
public void setCreated(Date created) {
this.created = created;
}
#Override
public String toString() {
return "Member [id=" + id + ", firstName=" + firstName + ", lastName=" + lastName + ", phoneNumber="
+ phoneNumber + ", created=" + created + "]";
}
}
How can i fix it?
I tried to inserted different numbers, but i always get a zero in the log.
Thanks
Column names of the query must match the setters in the target object.
Your query has a column named id but there is no setId method. You should either rename setUserId to setId or in the query give the alias user_id to id column.
From BeanPropertyRowMapper documentation:
Column values are mapped based on matching the column name as obtained from result set metadata to public setters for the corresponding properties. The names are matched either directly or by transforming a name separating the parts with underscores to the same name using "camel" case.

Ebean One to Many Mapping not working.

I am writing a web app that has products, customers, credit cards and a cart. Customer has a one to many mapping on both credit cards and carts. In my customer class i have a list and list. When i access customer.creditCardList everything works. When i try the same for customer.shoppingCartList i get this error.
error] Test models.ModelsTest.createAndRetrieveCart failed: javax.persistence.PersistenceException:
ERROR executing DML bindLog[] error[Field 'customer_id' doesn't have a default value]
Before i was getting no error but my shoppingCartList was always empty even with items in the database.
Here is my test function which is throwing the error:
#Test
public void createAndRetrieveCart(){
Customer walter = Customer.find.where().eq("email", "test#banananow.com").findUnique();
Product p1 = Product.find.where().idEq(1).findUnique();
Product p2 = Product.find.where().idEq(2).findUnique();
new ShoppingCart(walter, p1, 2).save();
new ShoppingCart(walter, p2, 3).save();
if(walter.shoppingCartList.size() < 2){
assert(false);
}
for(ShoppingCart cart : walter.shoppingCartList){
assertNotNull(cart.product.name);
assertNotNull(cart.product.price);
System.out.println(cart.product.name);
System.out.println(cart.product.price);
System.out.println(cart.quantity);
}
}
The error occurs on line 123 which is the first ShoppingCart.save()
The weird part is almost identical code for creditCardList passes and works properly. Here is that test
public void createAndAddCreditCard(){
Customer walter = Customer.find.where().eq("email", "tester#test.com").findUnique();
//Date date = new Date(2017, 10, 1);
//new CreditCard(1234567812345679L, walter, "walter wooodall", date, 21919, 123).save();
for(CreditCard card : walter.creditCardList){
System.out.println(card.number);
}
}
Here are my models:
Customer:
#Entity
public class Customer extends Model {
#Id
public int id;
public String email;
public String password;
public String name;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name="address_id")
public Address address;
public double balance;
#OneToMany(mappedBy = "customer")
public List<CreditCard> creditCardList;
#OneToMany(mappedBy = "customer")
public List<Basket> basketList;
#OneToMany(mappedBy = "customer")
public List<ShoppingCart> shoppingCartList;
public Customer(String email, String password, String name, Address address){
this.email = email.toLowerCase();
this.password = password;
this.name = name.toLowerCase();
this.address = address;
this.balance = 0.0;
//this.creditCardList = new ArrayList<CreditCard>();
//this.shoppingCartList = new ArrayList<ShoppingCart>();
}
public static Finder<String, Customer> find = new Finder<String, Customer>(String.class, Customer.class);
public static Customer authenticate(String email, String password) {
return find.where().eq("email", email)
.eq("password", password).findUnique();
}
public static Customer exists(String email) {
return find.where().eq("email", email).findUnique();
}
/*
public List<CreditCard> getCreditCardList(){
return CreditCard.find.where().eq("customer_id", this.id).findList();
}
*/
}
ShopppingCart:
#Entity
#Table(name="shopping_cart")
public class ShoppingCart extends Model{
#Id
public int id;
#ManyToOne
#JoinColumn(name = "customer_id", insertable = false, updatable = false)
public Customer customer;
#ManyToOne
#JoinColumn(name = "product_id", insertable = false, updatable = false)
public Product product;
public int quantity;
public ShoppingCart(Customer customer, Product product, int quantity){
this.customer = customer;
this.product = product;
this.quantity = quantity;
}
public static Finder<String, ShoppingCart> find = new Finder<String, ShoppingCart>(String.class, ShoppingCart.class);
}
Product:
#Entity
public class Product extends Model{
#Id
public int id;
public String name;
public Float price;
public String category;
public String subcategory;
#Column(name = "image_url")
public String imageUrl;
public String url;
#ManyToOne
public Store store;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "product")
public List<BasketProduct> basket_product;
#OneToMany(mappedBy = "product")
public List<ShoppingCart> shoppingCartList;
public Product(String name, Float price, String category, String subcategory, String imageUrl, String url, Store store){
this.name = name;
this.price = price;
this.category = category;
this.subcategory = subcategory;
this.imageUrl = imageUrl;
this.url = url;
this.store = store;
}
public Product(int id, String name, Float price, String category, String subcategory, String imageUrl, String url, Store store){
this.id = id;
this.name = name;
this.price = price;
this.category = category;
this.subcategory = subcategory;
this.imageUrl = imageUrl;
this.url = url;
this.store = store;
}
public static Finder<String, Product> find = new Finder<String, Product>(String.class, Product.class);
public static List<Product> getTopProducts(){
String sql = "select * from top_product";
SqlQuery sqlQuery = Ebean.createSqlQuery(sql);
List<SqlRow> sqlRows = sqlQuery.findList();
List<Product> productList = null;
if(sqlRows != null){
productList = new LinkedList<Product>();
for(SqlRow row : sqlRows){
int id = row.getInteger("id");
String name = row.getString("name");
float price = row.getFloat("price");
String category = row.getString("category");
String subcategory = row.getString("subcategory");
String imageUrl = row.getString("image_url");
String url = row.getString("url");
String storeId = row.getString("store_id");
productList.add(new Product(id, name, price, category, subcategory, imageUrl, url, Store.find.byId(storeId)));
}
}
return productList;
}
#Override
public String toString() {
return "Product{" +
"id=" + id +
", name='" + name + '\'' +
", price=" + price +
", category='" + category + '\'' +
", subcategory='" + subcategory + '\'' +
", image_url='" + imageUrl + '\'' +
", url='" + url + '\'' +
'}';
}
}
I have id, customer_id, product_id and quantity in my table with FK references to customer and product.
Anyone else have this problem and know how to solve??
It seems like following line doesn't read customer:
Customer walter = Customer.find.where().eq("email", "test#banananow.com").findUnique();
Your second test works good but you are querying for customer with different email there. So try to change previous line to:
Customer walter = Customer.find.where().eq("email", "tester#test.com").findUnique();
Socond problem is that you have:
#JoinColumn(name = "customer_id", insertable = false, updatable = false)
#JoinColumn(name = "product_id", insertable = false, updatable = false)
This is why these relations are not saved. Remove these lines.

Filter nested objects using Jackson's BeanPropertyFilter

I have the following objects:
#JsonFilter("myFilter")
public class Person {
private Name name;
private int age;
public Name getName() {return name;}
public void setName(Name name) {this.name = name;}
public int getAge() {return age;}
public void setAge(int age) {this.age = age;}
}
#JsonFilter("myFilter")
public class Name {
private String firstName;
private String lastName;
public String getFirstName() {return firstName;}
public void setFirstName(String firstName) {this.firstName = firstName;}
public String getLastName() {return lastName;}
public void setLastName(String lastName) {this.lastName = lastName;}
}
I wrote a method to marshall a Person object like this:
#Test
public void test() throws Exception {
Person person = new Person();
person.setAge(10);
Name name = new Name();
name.setFirstName("fname");
name.setLastName("lastname");
person.setName(name);
ObjectMapper mapper = new ObjectMapper();
FilterProvider filters = new SimpleFilterProvider().addFilter("myFilter",
SimpleBeanPropertyFilter.filterOutAllExcept("name.firstName"));
System.out.println(mapper.filteredWriter(filters).writeValueAsString(person));
}
What I'd like to see is JSON like this:
{"name":{"firstName":"fname"}}
Is something like that possible?
Ok, figured it out. Varargs would have made this a bit prettier, but oh well. Just hope I don't have two inner beans which have properties with the same name. I wouldn't be able to make the distinction between the two
FilterProvider filters = new SimpleFilterProvider()
.addFilter("myFilter", SimpleBeanPropertyFilter
.filterOutAllExcept(new HashSet<String>(Arrays
.asList(new String[] { "name", "firstName" }))));
There's a better way that solves problem with property name conflicts. Just add another filter to class Name ("nameFilter"):
#JsonFilter("personFilter")
public class Person {
private Name name;
private int age;
public Name getName() {return name;}
public void setName(Name name) {this.name = name;}
public int getAge() {return age;}
public void setAge(int age) {this.age = age;}
}
#JsonFilter("nameFilter")
public class Name {
private String firstName;
private String lastName;
public String getFirstName() {return firstName;}
public void setFirstName(String firstName) {this.firstName = firstName;}
public String getLastName() {return lastName;}
public void setLastName(String lastName) {this.lastName = lastName;}
}
And then add 2 filters, one for Person and one for Name:
FilterProvider filterProvider = new SimpleFilterProvider()
.addFilter("personFilter", SimpleBeanPropertyFilter.filterOutAllExcept("name"))
.addFilter("nameFilter", SimpleBeanPropertyFilter.filterOutAllExcept("firstName"));