Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
174 views
in Technique[技术] by (71.8m points)

spring - Java defining generic class as parameter for static method, to pass entity objects

Dear Stackoverflow community,

I am new to working with generics and have problems with using genericts correctly. What I want to do is, that a static method can take a generic Object as a parameter. My idea is, to pass Entity Objects as parameter and after return a UserDetailsImpl object. So I want to make this method able to handle different entity classes and dont write boilerplatecode. For this I write an easy Box class for it.

Box.java



    public class Box<T> {
    // T stands for "Type"
    private T t;
    public void set(T t) { this.t = t; }
    public T get() { return t; }
    
}

Now I try to use it to pass generic object as parameter in my UserDetailsImpl.java class in the static build method:

package com.yildiz.tradilianz.security.services;

import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

import com.fasterxml.jackson.annotation.JsonIgnore;

public class UserDetailsImpl implements UserDetails {
    private static final long serialVersionUID = 1L;
    
    private Long id;
    
    private String username;
    
    private String email;
    
    @JsonIgnore
    private String password;
    
    private Collection<? extends GrantedAuthority> authorities;
    
    public UserDetailsImpl(Long id, String username, String email, String password,
            Collection<? extends GrantedAuthority> authorities) {
        this.id = id;
        this.username = username;
        this.email = email;
        this.password = password;
        this.authorities = authorities;
    }
    
    public static UserDetailsImpl build(Box<Object> user) {
        List<GrantedAuthority> authorities = user.getRoles().stream()
                .map(role -> new SimpleGrantedAuthority(role.getName().name()))
                .collect(Collectors.toList());

        return new UserDetailsImpl(
                user.getId(), 
                user.getUsername(), 
                user.getEmail(),
                user.getPassword(), 
                authorities);
    }
    

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return authorities;
    }
    
    public Long getId() {
        return id;
    }
    
    public String getEmail() {
        return email;
    }

    @Override
    public String getPassword() {
        return password;
    }

    @Override
    public String getUsername() {
        return username;
    }

    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    @Override
    public boolean isEnabled() {
        return true;
    }
    
    @Override
    public boolean equals(Object o) {
        if (this == o)
            return true;
        if (o == null || getClass() != o.getClass())
            return false;
        UserDetailsImpl user = (UserDetailsImpl) o;
        return Objects.equals(id, user.id);
    }

}

Now the problem is, that the passed Object doesn't know the whole get() methods I try to access like user.getId(), user.getRoles(), user.getPassword() etc. I want that the generic Box Class contains any Object but how to declare this method I need to access from it?

Otherwise it ends up with "The method getRoles() is undefined for the type Box"

What I wanted to pass as generic Object is my customer entity class, but if it returns null instead i want to test if retailer entity class works and so on in **UserDetailsServiceImpl **:

package com.yildiz.tradilianz.security.services;

import org.apache.commons.validator.routines.EmailValidator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.yildiz.tradilianz.auth.User;
import com.yildiz.tradilianz.auth.UserRepository;
import com.yildiz.tradilianz.customer.Customer;
import com.yildiz.tradilianz.customer.CustomerDTO;
import com.yildiz.tradilianz.customer.CustomerRepository;

@Service
public class UserDetailsServiceImpl implements UserDetailsService {

    @Autowired
    CustomerRepository customerRepository;
    
    @Autowired
    CustomerDTO customerDTO;

    @Override
    @Transactional
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        // Check for username or email passed through username parameter
        boolean valid = EmailValidator.getInstance().isValid(username);
        if (valid == false) {
            
            /*
             * Build with UserDetailsImpl but if user for Customer class is null I want to try another repository and do 
             * something like this:
             * Retailer user = retailerRepository.findByUsername(username); And if it is not null
             * it should pass user Object which class is Retailer and so on.
             * 
             */
            Customer user = customerRepository.findByUsername(username);

            return UserDetailsImpl.build(user);
            
        } else {
            Customer user = customerRepository.findByEmail(username):

            return UserDetailsImpl.build(user);
            
        }
    }

}

customer entity class

package com.yildiz.tradilianz.customer;

import java.sql.Timestamp;
import java.util.HashSet;
import java.util.Set;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;

import org.hibernate.annotations.CreationTimestamp;

import com.yildiz.tradilianz.auth.ERole;


@Entity
public class Customer {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    @NotBlank
    @Size(max = 20)
    private String username;
    @NotBlank
    @Size(max = 120)
    private String password;
    @Column(nullable = false)
    private String givenName;
    @Column(nullable = false)
    private String surname;
    private String birthday;
    private String streetAddress;
    private String city;
    private String postalCode;
    @Column(updatable = false, nullable = false)
    private String email;
    private String phoneNumber;
    @CreationTimestamp
    private Timestamp timestamp;
    private Double balance;
    private Integer bonuspoints;
    private String role;

    protected Customer() {

    }

    public Customer(String username,String password, String givenName, String surname, String birthday, String streetAddress, String city,
            String postalCode, String email, String phoneNumber, Double balance, Integer bonuspoints, String role) {
        this.username = username;
        this.password = password;
        this.givenName = givenName;
        this.surname = surname;
        this.birthday = birthday;
        this.streetAddress = streetAddress;
        this.city = city;
        this.postalCode = postalCode;
        this.email = email;
        this.phoneNumber = phoneNumber;
        this.balance = balance;
        this.bonuspoints = bonuspoints;
        this.role = role;
    }

    @Override
    public String toString() {
        return ("Benutzername: "+username+ "Passwort: "+password+ "Vorname: " + givenName + " Nachname: " + surname +
                " Geburtstag: " + birthday + " Stra?e: "+ streetAddress + " Stadt: " + city + " Postleitzahl: " +
                postalCode + " E-Mail-Adresse: " + email+ " Telefonnummer: " + phoneNumber + "Kontostand: " + balance +
                " Bonuspunkte: " + bonuspoints+" Rolle:"+role);
    }
    public String getUsername() {
        return username;
    }
    
    public String getPassword() {
        return password;
    }

    public Long getId() {
        return id;
    }

    public String getGivenName() {
        return givenName;
    }

    public String getSurname() {
        return surname;
    }

    public String getBirthday() {
        return birthday;
    }

    public String getStreetAddress() {
        return streetAddress;
    }

    public String getCity() {
        return city;
    }

    public String getPostalCode() {
        return postalCode;
    }

    public String getEmail() {
        return email;
    }

    public String getPhoneNumber() {
        return phoneNumber;
    }

    public Timestamp getTimestamp() {
        return timestamp;
    }

    public Integer getBonuspoints() {
        return bonuspoints;
    }

    public Double getBalance() {
        return balance;
    }
    
    public String getRole() {
        return role;
    }
    

    public void setUsername(String username) {
        this.username = username;
    }
    
    public void setPassword(String password) {
        this.password = password;
    }

    public void setGivenName(String givenName) {
        this.givenName = givenName;
    }

    public void setSurname(String surname) {
        this.surname = surname;
    }

    public void setBirthday(String birthday) {
        this.birthday = birthday;
    }

    public void setStreetAddress(String streetAddress) {
        this.streetAddress = streetAddress;
    }

    public void setCity(String city) {
        this.city = city;
    }

    public void setPostalCode(String postalCode) {
        this.postalCode = postalCode;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public void setPhoneNumber(String phoneNumber) {
        this.phoneNumber = phoneNumber;
    }

    public void setBalance(Double balance) {
        this.balance = balance;
    }

    public void setBonuspoints(Integer bonuspoints) {
        this.bonuspoints = bonuspoints;
    }
    
    public void setRole(String role) {
        this.role = role;
    }

}

**

Can you pls give me tipps how I do it the right way?

question from:https://stackoverflow.com/questions/65888941/java-defining-generic-class-as-parameter-for-static-method-to-pass-entity-objec

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

in your build() method, you are passing Box, so it only knows the type as Object.

public static UserDetailsImpl build(Box<Object> user)

when you try to access it, you are trying to access the methods from type Customer, which it will not have any clue what methods are associated with Customer object. (user reference will only know about Box class methods)

so, what you need to do is change Box<Object> to Box<Customer> and then access the Customer's methods using

user.get().getId() etc.

here user.get() will return the underlying type object and you will have access to its methods.

or what you can also do is if you want the generic type to be a specific instance type, you can change your Box class implementation to be (extends T type to an instance of that class), for e.g. Customer in your case. (you ca create an interface or abstract class that will have methods that you are trying to use)

public class Box< T extends Customer>

public class Box<T extends CustomerInterface>  etc.

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...