RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 959711
Accepted
Orkhan Hasanli
Orkhan Hasanli
Asked:2020-03-22 03:29:23 +0000 UTC2020-03-22 03:29:23 +0000 UTC 2020-03-22 03:29:23 +0000 UTC

如何在 Spring 中克服 UnsupportedOperationException: null?

  • 772

我遇到了一个相当奇怪的问题。有一个实体 User 和这个类的对象需要通过多对多的关系相互连接。因此,除了主表“user”之外,还应该出现另外 2 个表“customer_authors”“author_customers”

@Entity
public class User {

  @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    // ID пользователя
    private Long userId;


    // "customer_authors"
    @ManyToMany(cascade=CascadeType.ALL)
    @JoinTable(name = "customer_authors",
            joinColumns = @JoinColumn(name = "customer_id"),
            inverseJoinColumns = @JoinColumn(name = "author_id"))
    private List<User> authorsList = new ArrayList<>();

    // "author_customers"
    @ManyToMany(cascade=CascadeType.ALL)
    @JoinTable(name = "author_customers",
            joinColumns = @JoinColumn(name = "author_id"),
            inverseJoinColumns = @JoinColumn(name = "customer_id"))
    private List<User> customersList = new ArrayList<>();

    // getters, setters and other data.
}

在我的代码中没有任何地方使用数组 asList() / 创建了一个固定大小的列表。确切地说,根据谷歌搜索和stackoverflow,这是类似错误的原因......

就我而言,如果我在 @Service UserService 中使用类似的代码:

user.setUserEmail(userEmail);
user.setUserPassword(passwordEncoder.encode(userPassword));
userRepository.save(user);

User referrer = userRepository.findUserByUserId(referrerId);
referrer.getAuthorsList().add(user);
userRepository.save(referrer);

然后我得到相应的错误 -

UnsupportedOperationException

// excerpt
java.lang.UnsupportedOperationException: null
  at com.sun.proxy.$Proxy142.save(Unknown Source) ~[na:na]
  at info.md7.textpool.services.UserService.addUser(UserService.java:252) ~[classes/:na]
  at info.md7.textpool.controllers.UserController.userRegistration(UserController.java:54) ~[classes/:na]

但同时,如果你在控制器中使用这样的东西进行测试:

User customer = (User) userService.findUserByEmail(currentUser.getUsername());
    User author = userRepository.findByUserEmail("sukkivulmo@desoz.com");
    customer.getAuthorsList().add(author);
    userRepository.save(author);

然后确实将引用者 ID 和用户 ID 的必要信息添加到表中。

可能是什么错误?也许有人经历过这个并且知道如何解决它?先感谢您!

来自 UserService 的完整方法片段:

public boolean addUser(  //todo добавить тип работы
          String userFullname,
          String userEmail,
          String userPassword,
          String prefLangs,
          String prefCats,
          Double paymentCost,
          String paymentMethod,
          String paymentWallet,
          Long referrerId,
          User user
  ) throws MessagingException {

    User userFromDbEmail = userRepository.findByUserEmail(userEmail);
    User referrer = userRepository.findUserByUserId(referrerId);

    if(userFromDbEmail != null) {
      return false;
    }

    /*
     * Проверяем наличие данных в полях prefLang, prefCats, paymentCost, paymentMethod, paymentWallet.
     * И если они имеются в одном из полей, то регистрируем пользователя, как Автора.
     * В противном случае, создаем нового Заказчика.
     *
     */

    if(
        prefLangs != null && !prefLangs.isEmpty() ||
        prefCats != null && !prefCats.isEmpty() ||
        paymentCost != null ||
        paymentMethod != null && !paymentMethod.isEmpty() ||
        paymentWallet != null && !paymentWallet.isEmpty()
    ) {

      user.setUserFullname(userFullname);
      user.setUserEmail(userEmail);
      user.setUserPassword(passwordEncoder.encode(userPassword));
      user.setRegDate(LocalDateTime.now());
      user.setUserActive(false);
      user.setRoles(Collections.singleton(Role.AUTHOR));
      user.setActivationCode(UUID.randomUUID().toString());
      user.setUserMode("author");
      user.setReceiveEmails(true);

      // Если пользователь был приглашен, то находим реферрера и добавлем в его список нового пользователя
      User referrer = userRepository.findUserByUserId(referrerId);
      user.setReferrerId(referrer);

      userRepository.save(user);


      /*  Добавляем метаданные для юзера
          С связи с особенностями верстки, данные скриптом вставляю в hidden input поле, после чего
          получаю String разделенный запятыми и разобрав добавляю данные в user_meta
       */
      assert prefLangs != null;
      String[] prefLang = prefLangs.split(",");
      for (String metaValue : prefLang) {
        UserMeta userMeta = new UserMeta();
        String metaKey = "prefLang";
        userMeta.setMetaKey(metaKey);
        userMeta.setMetaValue(metaValue);
        userMeta.setUser(user);
        userMetaRepository.save(userMeta);
      }

      assert prefCats != null;
      String[] prefCat = prefCats.split(",");
      for (String metaValue : prefCat) {
        UserMeta userMeta = new UserMeta();
        String metaKey = "prefCat";
        userMeta.setMetaKey(metaKey);
        userMeta.setMetaValue(metaValue);
        userMeta.setUser(user);
        userMetaRepository.save(userMeta);
      }

      UserMeta paymentMeta = new UserMeta();
      paymentMeta.setMetaKey(paymentMethod);
      paymentMeta.setMetaValue(paymentWallet);
      paymentMeta.setUser(user);
      userMetaRepository.save(paymentMeta);

      if(paymentCost != null) {
        UserMeta paymentCostMeta = new UserMeta();
        paymentCostMeta.setMetaKey("paymentCost");
        paymentCostMeta.setMetaValue(paymentCost.toString());
        paymentCostMeta.setUser(user);
        userMetaRepository.save(paymentCostMeta);
      }


      referrer.getAuthorsList().add(user);
      userRepository.save(referrer);

    } else {

      user.setUserFullname(userFullname);
      user.setUserEmail(userEmail);
      user.setUserPassword(passwordEncoder.encode(userPassword));
      user.setRegDate(LocalDateTime.now());
      user.setUserActive(false);
      user.setRoles(Collections.singleton(Role.CUSTOMER));
      user.setActivationCode(UUID.randomUUID().toString());
      user.setUserMode("customer");
      user.setReceiveEmails(true);

      // Если пользователь был приглашен, то находим реферрера и добавлем в его список нового пользователя
      User referrer = userRepository.findUserByUserId(referrerId);
      user.setReferrerId(referrer);

      userRepository.save(user);


      referrer.getCustomersList().add(user);
      userRepository.save(referrer);

    }

    return true;
  }
java
  • 2 2 个回答
  • 10 Views

2 个回答

  • Voted
  1. Alexander Kukhtin
    2020-03-22T07:56:41Z2020-03-22T07:56:41Z

    您需要查看Array list的方向,它返回list,它Arrays.asList返回一个您无法添加元素的固定大小的列表。可以像这样创建一个可变列表

    List<Integer> list1 = new ArrayList<>(Arrays.asList(10,20,60,30,22,70,89));
    
    • 3
  2. Best Answer
    Михаил Ребров
    2020-03-23T15:21:21Z2020-03-23T15:21:21Z

    UnsupportedOperationException 来自哪里?

    Java 中的集合可以有可选的方法。
    当调用此实现中未提供其实现的方法时,将抛出以下内容UnsupportedOperationException:

    public interface Iterator<E> {
        //...
        default void remove() {
            throw new UnsupportedOperationException("remove");
        }
        //...
    } 
    

    接口中此类方法的存在可能令人费解,但在这种情况下,据我了解,这是由于与旧版本 Java 的向后兼容性。

    正如其他人所说,集合既可以是可变的,也可以是不可变的。然而,与普遍看法相反,在这种情况下,异常不是由于使用Arrays.asList(作者明确地用新对象初始化字段ArrayList'а)。
    虽然它非常非常接近,显然有必要朝这个方向挖掘。

    不幸的是,所有的注意力都集中在两个领域:authorsList和customersList.
    有非常可疑的镜像链接,甚至有级联操作,在这种特殊情况下显然不能以那种形式应用。而且,删除时cascade=CascadeType.ALL错误消失了。我们稍后会回到他们身边。

    错误更加平淡无奇:

    user.setRoles(Collections.singleton(Role.AUTHOR));
    

    作者显式地创建了一个单例(不可修改的集合)并将其传递给角色列表。

    之后,这个对象就被成功保存了。

    在我们将此用户添加到另一个用户的受邀客户端列表并保存之前使用 hibernate 获得的第二个用户(邀请者)之后,就会出现错误。

    保存第二个用户及其与第一个用户的关系后,hibernatecascade=CascadeType.ALL会查看customersList并开始更新给定列表中的第一个用户对象。覆盖在集合的字段中找到的所有字段 hibernate 清理然后再次检索其中的数据。所以它涉及roles一个单例的字段,它位于第一个用户中,而该用户又位于第二个用户的列表中。试图清除它并得到UnsupportedOperationException。

    要解决此问题,只需编写:

      user.getRoles().add(Role.AUTHOR);
    

    在这种情况下,cascade=CascadeType.ALL这并不重要。
    但是,你不能就这样离开它。因为,在删除邀请用户时,所有作者和客户都会被自动删除,在我看来,这与作者的意图不符。

    以上这两个字段(authorsList和 customersList)至少应该放

    @ManyToMany(cascade={CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH}, targetEntity = User.class)
    

    老实说,这些字段是多余的,你可以去掉它们。
    毕竟,对于每个受邀用户,我们都设置了referrer(受邀用户)。
    因此,我们可以添加一个逆属性invitedUsers并按角色过滤它。
    或者只是通过推荐人和角色选择用户。

    • 2

相关问题

Sidebar

Stats

  • 问题 10021
  • Answers 30001
  • 最佳答案 8000
  • 用户 6900
  • 常问
  • 回答
  • Marko Smith

    根据浏览器窗口的大小调整背景图案的大小

    • 2 个回答
  • Marko Smith

    理解for循环的执行逻辑

    • 1 个回答
  • Marko Smith

    复制动态数组时出错(C++)

    • 1 个回答
  • Marko Smith

    Or and If,elif,else 构造[重复]

    • 1 个回答
  • Marko Smith

    如何构建支持 x64 的 APK

    • 1 个回答
  • Marko Smith

    如何使按钮的输入宽度?

    • 2 个回答
  • Marko Smith

    如何显示对象变量的名称?

    • 3 个回答
  • Marko Smith

    如何循环一个函数?

    • 1 个回答
  • Marko Smith

    LOWORD 宏有什么作用?

    • 2 个回答
  • Marko Smith

    从字符串的开头删除直到并包括一个字符

    • 2 个回答
  • Martin Hope
    Alexandr_TT 2020年新年大赛! 2020-12-20 18:20:21 +0000 UTC
  • Martin Hope
    Alexandr_TT 圣诞树动画 2020-12-23 00:38:08 +0000 UTC
  • Martin Hope
    Air 究竟是什么标识了网站访问者? 2020-11-03 15:49:20 +0000 UTC
  • Martin Hope
    Qwertiy 号码显示 9223372036854775807 2020-07-11 18:16:49 +0000 UTC
  • Martin Hope
    user216109 如何为黑客设下陷阱,或充分击退攻击? 2020-05-10 02:22:52 +0000 UTC
  • Martin Hope
    Qwertiy 并变成3个无穷大 2020-11-06 07:15:57 +0000 UTC
  • Martin Hope
    koks_rs 什么是样板代码? 2020-10-27 15:43:19 +0000 UTC
  • Martin Hope
    Sirop4ik 向 git 提交发布的正确方法是什么? 2020-10-05 00:02:00 +0000 UTC
  • Martin Hope
    faoxis 为什么在这么多示例中函数都称为 foo? 2020-08-15 04:42:49 +0000 UTC
  • Martin Hope
    Pavel Mayorov 如何从事件或回调函数中返回值?或者至少等他们完成。 2020-08-11 16:49:28 +0000 UTC

热门标签

javascript python java php c# c++ html android jquery mysql

Explore

  • 主页
  • 问题
    • 热门问题
    • 最新问题
  • 标签
  • 帮助

Footer

RError.com

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

帮助

© 2023 RError.com All Rights Reserve   沪ICP备12040472号-5