I am a beginner in Java and have below 2 Beans/POJOS in my existing company application:
User
public class User {
public int getUserId() {
return userId;
}
public void setUserId(int userId) {
this.userId = userId;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
}
Employee
public class Employee {
public int getUserId() {
return userId;
}
public void setUserId(int userId) {
this.userId = userId;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
}
I want to cast User to Employee because in the application I would be receiving the User object in the one of the methods which is used for persisting into the database using hibernate3 xml mapping method. HIbernate mapping exists for the Employee object and not for User. Hence I tried the conversion using the below concept that everything in java is an object but still it is giving the RuntimeException of ClassCastException :
User u = new User(12,"johnson","pam",new Date());
Object o = u;
Employee e=(Employee)o;
Is there any other way to solve this problem? There is no option to change the existing class hierarchies or include any additional inheritance structure.
You cannot cast objects at all in Java. You can cast a reference, to a type implemented by the referenced object.
What you can do is convert from one object to a new object. If you cannot modify the classes, you can write an external converter. For example:
public class EmployeeFactory {
public static Employee toEmployee( User user ) {
Employee emp = new Employee();
emp.setUserId( user.getUserId() );
emp.setUserName( user.getUserName());
return emp;
}
}
You can't cast user object to an employee object as they don't have any relation. You should have some Mapper class which will map a User object to Employee Object.
class UserToEmployee{
public Employee map(User user){
Employee e = new Employee();
e.setUserId(user.getUserId());
// so on set all the required properties
return e;
}
}
Then use it like:
User u = new User(12,"johnson","pam",new Date());
UserToEmployee mapper = new UserToEmployee();
Employee e = mapper.map(u)
Because Employee and User is completely two different object, so you cannot cast like your case
A simple example
User
public class User {
public int getUserId() {
return userId;
}
public void setUserId(int userId) {
this.userId = userId;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
}
Employee
public class Employee extends User {
//constructor
}
Then you can do this
Employee e = new Employee();
Object o = e;
User = (Employee) o;
Of course, In this case, you cannot do the opposite way: cast User to Employee
Hope this little example help you understand clearly about the case.
In java, an easy way to think about casting objects is: "Am I lying?"
Ie if I cast the User to Employee, I'm saying the User is an Employee. Am I lying? If so, the cast will work. If not, then it wont. Now, according to your logic, you want all Employees to be Users. To establish an "is-a" relationship, you can use the word "extends"
class User{
//Your things
}
class Employee extends User{
//More employee-specific things
}
Now if you do
User john=new User(//args);
You can do
if(john instanceof Employee){//Make sure john is an employee
Employee johnEmployee=(Employee)john
}
All casting is is relabeling an object. But you can't lie about anything that isn't established when the object is made.
Related
How can I fetch custId from a list which has a generic interface? I tried fetching custId via list.getClass.getField("custId") but unfortunately, the value is not coming.
class Emp implements CommonDto {
private String CustId;
private String EmpId;
private String EmpName;
}
class Student implements CommonDto{
private String CustId;
private String StudentId;
private String StudentName;
}
public interface CommonDto {
}
public class TestApplication {
public static void main(String[] args) throws NoSuchFieldException, IllegalArgumentException {
Emp emp = new Emp(1 , 100, "ayush");
List<Emp> temp = new ArrayList<>() ;
temp.add(emp);
List<CommonDto> commonList = new ArrayList<>();
commonList.add(temp);
for(CommonDto comm : commonList)// is this the right way to fetch CustId
{
// fetch cusId from every domain and add it to new list and return that list
}
}}
In order to access the CustId field you must first recognize that that field does not belong to the CommonDTO class. Therefore, there is no guarantee that a given instance will have that field. If every instance is supposed to have the field then move that field to that class to properly model the data.
Given the existing models, there is a CustId field in both Emp and Student but these are NOT the same field. You can test the data type of a given instance, cast it, and call the appropriate method.
public String getCustId(CommonDTO dto) {
if (dto instanceof Emp) {
return ((Emp)dto).getCustId();
}
if (dto instanceof Student) {
return ((Student)dto).getCustId();
}
return null;
}
If you have leeway to alter the data model then you can move CustId to the parent class (i.e. CommonDTO). Let's assume that his class is provided and you cannot change it. However, you still have leeway to alter the Emp and Student models.
You could also define a common interface that defines the property via method and have each of the classes implement that interface.
public interface Custmor {
public String getCustId();
}
public class Emp implements Customer {
private String custId;
public String getCustId() { return custId; }
...
}
public class Student implements Customer {
private String custId;
public String getCustId() { return custId; }
...
}
Then you can handle the data via the interface.
public String getCustId(CommonDTO dto) {
if (dto instanceof Customer) {
return ((Customer)dto).getCustId();
}
return null;
}
Alternatively, you could create a Customer class that extends the CommonDTO and serves as a base class for both of these...
public class Customer extends CommonDTO {
private custId;
public String getCustId() { return custId; }
...
}
And alter the Emp and Student classes to extend this...
public class Emp extends Customer { ... }
public class Student extends Customer { ... }
In either case (interface or common base class), you can then use instanceof to determine if a given CommonDTO instance is a Customer and cast it to access the method. You can use the Stream API to easily pull the custIds from the Customers in a List<CommonDTO>:
List<String> customerIds = commonList.stream()
.filter(c -> c instanceof Customer) // filter out the non-Customer elements out of the streawm
.map(c -> (Customer)c) // cast the CommonDTO to a Customer
.map(c -> c.getCustId()) // get the custId
.collect(Collectors.toList()); // capture the custIds in a List
p.s. suggest that you adhere to Java naming conventions (e.g. variable names begin with lower case letter).
I have a class called User.java
public class User {
public User(Context context) {
}
public User() {
}
public void getUserId(){
}
public void getUserName(){
}
}
If I create an object of user class then I can reach to all methods such as getUserId and getUserName
User user_1 = new User(this);
user_1.getUserId();
user_1.getUserName();
User user_2 = new User();
user_2.getUserId();
user_2.getUserName();
The main question is can I get getUserName only if I called a constructor that has one parameter? But if I call a constructor that does not have a parameter then I can't get getUserName. Is it possible in Java?
There are multiple ways to achieve (roughly) what you want.
The easy, but possibly annoying way is to throw an Exception whenever a "forbidden" method is called:
public String getUserName(){
if (someRequiredContext == null) {
throw new IllegalStateException("method not allowed!");
}
// do stuff
}
This "works", but doesn't help the user avoid calling those methods, since there's no easy way for them to know if they can call getuserName on a given User object.
The more involved version would be to have two classes (for example User and UserWithContext), but then you can't instantiate them the right way. But you could use factory methods instead of constructors:
public abstract class User {
User() { ... };
public static User createUser() {
return new BasicUser();
};
public static UserWithContext createUser(Context context) {
return new UserWithContext(context);
}
public String getId() { ... }
}
class BasicUser extends User { // this class need not be public!
}
public class UserWithContext extends User {
UserWithContext(Context context) { ... }
public String getuserName() { ... };
}
This way the type will inform the users of your API which methods are allowed with a given User object.
No, it is not possible. But you could use interfaces to say for instance LimitedUser and FullUser
public interface LimitedUser {
int userId();
}
public interface FullUser extends LimitedUser {
String getUsername();
}
Then use factory methods on for instance the User implementation
public class User implements FullUser {
private final int id;
private final String username;
private User(int id, String username) {
this.id = id;
this.username = username;
}
public static LimitedUser createLimitedUser(int id) {
return new User(id, null);
}
public static FullUser createFullUser(int id, String username) {
return new User(id, username);
}
public int getId() {
return id;
}
public String getUsername() {
return username;
}
}
I'm writing a program which consists of multiple classes. One class is called "User" and the other one is called "userGroup". I'm trying to import a variable which is contained within a constructor from the User class and use it in the userGroup class.
I've tried the following code:
User userRetrieve = new User();
userRetrieve.User();
This code doesn't seem to work, although I have seen in various tutorials that this is how you would retrieve data from another class. The second line has ".User()" because the constructor is also called User but I am not sure if this is correct and even if it was the initial problem of the program not recognizing the first line would still remain.
I'll show the code form both classes for extra information which may show where I have gone wrong:
User class:
public class User {
String username;
String userType;
String name;
public User() {
username = "x";
userType = "y";
name = "z";
}
public String getUsername() {
return username;
}
public String getUserType() {
return userType;
}
public String getName() {
return name;
}
public String setUserType(String admin) {
return userType = admin;
}
}
userGroup class:
import java.util.ArrayList;
public class userGroup {
String User;
ArrayList<User> userArray = new ArrayList<>();
Integer user0;
public void addSampleData() {
userArray.add(new User());
}
public void getUser(User user0) {
user0 = userArray.get(0);
}
public void printusername() {
System.out.println(user0.getUserName()); // x
}
}
I'm trying to use the username and userType variables in the constructor from the User class.
P.S Apologies for any formatting/indentation errors.
You have misunderstrood some concepts. Firstly the User() method is the constructor so when you do User user = new User() that method is called. I suggest this change to your user class
public class User {
private String username;
private String userType;
private String name;
// Use constructor to pass data to your class
public User(String username, String userType, String name) {
this.username = username;
this.userType = userType;
this.name = name;
}
public String getUsername() {
return username;
}
public String getUserType() {
return userType;
}
public String getName() {
return name;
}
public String setUserType(String admin) {
return userType = admin;
}
}
Now you can create your array and add a user, then retrieve its information
List<User> users = new ArrayList<User>();
users.add(new User("x", "y", "z"));
users.get(0).getUsername(); // returns "x"
Make a list of users
List<User> users = new ArrayList<User>()
Add a user
users.add(new User());
Get a user (lists and arrays are zero-indexed)
User user0 = users.get(0);
Print some properties
System.out.println(user0.getUserName()); // x
You could use the get methods you created in the constructor class?
So if you want to get the username and the userType just create a new variable using the get method
User userRetrieve = new User();
String username = userRetrieve.getUsername();
String userType = userRetrieve.getUserType();
Or alternatively you could just directly access the variables:
User userRetrieve = new User();
String username = userRetrieve.username;
String userType = userRetrieve.userType;
User userRetrieve = new User();
On this line you are instantiating a new object of type Person,
you do this by calling the constructor associated with this particular class.
After you have done this it is possible to acces parameters by calling the various methods you have defined in the Person class. So in your case you should use userRetrieve.getUsername() and so on.. you will however need to declare a variable in the calling class to store these values in.
I'm developing a service using apache thrift. I have a service named getUser which returns User object. I couldn't find any way to define user-defined data type as a return type for my service defined in .thrift file.
user.thrift file looks like:
service UserService
{
User getUser(1:i32 userId),
}
When I am compiling the user.thrift to generate java source code, I am getting "Type "User" has not been defined" error. Can anyone please help me, how to represent this user-defined java object as a data type in thrift.
The getUser method code in service implementation class:
#Override
public User getUser(int user id) throws TException {
// here is the code that fetch the user object from database
return user;
}
This is my User class, whose object is being returned by service getUser:
public class User {
private int userId;
private String name;
private String city;
private String country;
public int getUserId() {
return userId;
}
public void setUserId(int userId) {
this.userId = userId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
}
The relevant IDL could look like this:
struct User {
1 : i32 userId
2 : string name
3 : string city
4 : string country
}
So that's pretty straightforward. With that, you have two options:
use the Thrift-generated class as the data object, replacing your existing class
write some code that converts the data back and forth.
Both options have their pros and cons. With the first approach, you will lose the getter-only for the Id, because the field must be read/writable. But you don't have to convert any data.
The second approach leaves you with the getter/setter structure you have right now, with some minor modifications (the factory pattern could be worth a look). You pay that with the burden of additional data conversion from Thrift into your class and back.
It depends on the exact requirements, which option is the better one for your case.
I am coding in blueJ. My objectives are this: 1)Write a User class
A User:
has a username e.g 'fj3'
has a userType which can be: 'user', 'editor' or 'admin'
has a name e.g 'Francis'
has a constructor which takes the username, userType and name as parameters
has a getUsername() method
has a getUserType() method
has a getName() method
has a setUserType() method which takes one of the user types as a parameter
2)Write a UserGroup class
The UserGroup class must have an ArrayList of Users.
Write a constructor for the UserGroup class. It should instantiate the ArrayList.
In UserGroup write a method called .addSampleData() which creates 10 Users and using the ArrayList's add() method put the 10 new User objects into the ArrayList.
In UserGroup write a getUser method which takes an int as a parameter and returns the User in that slot of the ArrayList.
In UserGroup write a printUsernames() method in UserGroup:
Using an enhanced for loop (see above), loop through the ArrayList and print the username and userType of each user in the ArrayList.
What I have so far is:
package user;
public class User{
public enum UserType{
ADMIN, EDITOR, USER;
}
private String id;
private UserType userPermissions;
private String actualName;
public User(String username, UserType userType, String name){
id = username;
userPermissions = userType;
actualName= name;
}
public String getUsername(){
return id;
}
public UserType getUserType(){
return userPermissions;
}
public String getName(){
return actualName;
}
public void setUserType(UserType input){
userPermissions = input;
}
}
And my UserGroup class:
package user;
import java.util.*;
import user.User.UserType;
public class UserGroup{
private ArrayList<User> people;
public UserGroup(){
people = new Arraylist<User>();
}
public static void addSampleData(String username, UserType userType, String name){
people.add(new User(username, userType,name));
}
public User get(int){
return User;
}
public void printUsernames(){
for (User user: groupArray){
System.out.printf("%s %s\n", user.getUsername(), user.getuserType);
}
}
}
This is obviously far from being complete but I am completely stuck. My first problem is that I am unsure how to write the get method for this. Please help me with this!! I think my User class is fine but my UserGroup class is nowhere near completing all the objectives and I don't know how to do them!!
Looks good so far, some corrections:
The addSampleData()method should not be static, as it uses a non-static member of the class. The request also states it to add the sample data itself.
The getUser() is pretty straight forward then.
The printUsernames()method uses an unknown member.
public void addSampleData() {
people.add(new User("pe3", UserType.ADMIN,"Peter"));
people.add(new User("u987", UserType.EDITOR,"Udo"));
people.add(new User("frank123", UserType.USER,"Frank"));
// repeat ...
}
public User getUser(int idx) {
return people.get(idx);
}
public void printUsernames(){
for (User user: people){
System.out.printf("%s %s\n", user.getUsername(), user.getuserType);
}
}
In a main method then:
UserGroup grp = new UserGroup();
grp.addSampleData();
grp.printUsernames();
User u1 = grp.getUser(0);