繁体   English   中英

Java 定义通用 class 作为 static 方法的参数,以传递实体对象

[英]Java defining generic class as parameter for static method, to pass entity objects

亲爱的 Stackoverflow 社区,

我是使用 generics 的新手,并且在正确使用泛型时遇到问题。 我想要做的是,static 方法可以将通用 Object 作为参数。 我的想法是,将实体对象作为参数传递,然后返回 UserDetailsImpl object。 所以我想让这个方法能够处理不同的实体类并且不编写样板代码。 为此,我为它编写了一个简单的 Box class。

盒子.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; }
    
}

现在我尝试使用它在我的UserDetailsImpl.java class 方法中将通用 object 作为参数传递:

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);
    }

}

现在的问题是,通过的 Object 不知道我尝试访问的整个 get() 方法,如 user.getId()、user.getRoles()、user.getPassword() 等。我想要通用 Box Class包含任何 Object 但如何声明我需要从中访问的方法?

否则它会以“方法 getRoles() 未定义类型 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);
            
        }
    }

}

客户实体 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;
    }

}

**

你能给我提示我如何以正确的方式做到这一点吗?

在您的 build() 方法中,您传递的是 Box,因此它只知道类型为 Object。

public static UserDetailsImpl build(Box<Object> user)

当您尝试访问它时,您正在尝试访问来自客户类型的方法,它不会知道哪些方法与客户 object 相关联。 (用户参考只会知道 Box class 方法)

因此,您需要做的是将Box<Object>更改为Box<Customer>然后使用访问客户的方法

user.get().getId() etc.

这里 user.get() 将返回底层类型 object 并且您将可以访问它的方法。

或者您还可以做的是,如果您希望泛型类型成为特定的实例类型,您可以将 Box class 实现更改为(将 T 类型扩展到该类的实例),例如您的情况下的客户。 (您可以创建一个接口或抽象 class 将具有您尝试使用的方法)

public class Box< T extends Customer>

public class Box<T extends CustomerInterface>  etc.

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM