当前位置: 首页 > 知识库问答 >
问题:

Java 定义泛型类作为静态方法的参数,传递实体对象

苏高远
2023-03-14

亲爱的堆栈溢出社区,

我是泛型的新手,在正确使用泛型方面有问题。我想做的是,静态方法可以将泛型对象作为参数。我的想法是,将实体对象作为参数传递,然后返回UserDetailsImpl对象。所以我想让这个方法能够处理不同的实体类,而不是编写boilerplatecode。为此,我为它编写了一个简单的Box类。

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

现在我尝试使用它在静态构建方法中的 UserDetailsImpl.java 类中将泛型对象作为参数传递:

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

}

现在的问题是,传递的对象不知道我尝试访问的整个get()方法,如user.getId(),user.getRoles(),user.getPassword()等。我希望通用 Box 类包含任何对象,但如何声明我需要从中访问的此方法?

否则,它以“方法getRoles()未定义类型Box”结束

我想作为通用对象传递的是我的客户实体类,但如果它返回null,我想在**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);
            
        }
    }

}

客户实体类

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

}

**

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

共有1个答案

洪弘毅
2023-03-14

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

< code > public static user details simple build(Box

当您尝试访问它时,您正在尝试从 Customer 类型访问方法,它不知道哪些方法与 Customer 对象相关联。(用户参考只会知道Box类方法)

所以,你需要做的是改变盒子

user.get().getId() etc.

这里user.get()将返回底层类型对象,您将可以访问其方法。

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

public class Box< T extends Customer>

public class Box<T extends CustomerInterface>  etc.

 类似资料:
  • 问题内容: 问题摘要: 我想将具有类型参数(例如)的类作为类型参数传递给泛型方法。 假设我有一个方法: 当然,此方法对于任何类型的类都可以正常使用。我可以这样调用该方法,例如: 问题: 我发现我不能这样做: 从句法上讲,这显然是无效的。但是,我不确定如何实现这样的目标。我当然可以通过,但是泛型类型的添加使其在语法上不再有效,并且我想不出解决方法。 唯一的直接解决方案是这样的事情(看起来很愚蠢):

  • 问题总结:我想传递一个带有类型参数(如

  • 我写了以下方法 我如何将不同的枚举类型传递给第二个参数?我知道我不能创建枚举的实例,但初始化枚举意味着我将传递一个值,而不是整个初始化的枚举,如下所示...其他枚举也将传递给相同的方法以实现组合细节

  • 问题内容: 您认为可以创建类似的东西吗? 问题答案: 是的你可以。 用法示例:

  • 问题内容: 在Java中,我希望具有以下内容: 但是我明白了 我对基本用途以外的泛型没有什么了解,因此对此没有多大意义。我无法在互联网上找到有关该主题的很多信息,这无济于事。 有人可以通过类似的方式澄清这种使用是否可行吗?另外,为什么我最初的尝试失败了? 问题答案: 你不能在静态方法或静态字段中使用类的泛型类型参数。该类的类型参数仅在实例方法和实例字段的范围内。对于静态字段和静态方法,它们在类的所

  • 问题内容: 当我定义一个自定义类型时,基础类型的类型似乎对我是否可以按原样将其传递给函数还是需要对其进行转换有所不同。 问题是: 为什么和起作用,但不起作用? https://play.golang.org/p/buKNkrg5y- 在这里,当我运行此函数时,它会抱怨,尽管它是基础类型。但是当我打电话或他们成功运行时。 问题答案: 和 您的新类型是2种不同的不同类型。在预期的地方,您必须传递typ

  • 我有一个用例,其中一个类存在于一个包的两个版本中。 到目前为止还不错(我相信)。 然后我有一个使用该类的应用程序,为了避免为不同的包版本重写应用程序,我想传递应该使用的类(即感兴趣的包)作为应用程序的参数。所以像这样的东西 我相信我可以把这个叫做如果我在构造函数中传递的实例,那么我会通过实例对象调用静态方法,不是吗? 另一方面,在上面的示例中,是一个类对象,因此我不能像上面那样调用静态方法。 这是

  • 错误:不兼容的类型:DrawerListItem不能转换为Cap#1,其中Cap#1是一个新的类型变量:Cap#1从capture的capture扩展了BaseListItem?扩展基线 我不明白为什么这是错误的。,。我试着阅读了其他关于泛型类型和类型参数的文章,但它们似乎都没有解决这个问题。