【问题标题】:Spring 5 immutable form to use an all arg constructor when there is No argument constructor as wellSpring 5 不可变形式在没有参数构造函数时使用全参数构造函数
【发布时间】:2019-08-07 21:56:03
【问题描述】:

在一个不可变的类/对象中,我有一个无参数构造函数将值初始化为默认值/null,另一个必需的参数构造函数将所有值初始化为来自构造函数的参数。

当使用表单绑定时(通过在控制器中指定请求参数),spring 总是调用无参数构造函数并且不初始化值。如何确保 spring 只调用所需的参数构造函数?

这是在春季版本 5.1.5 中。我也尝试在“必需的参数构造函数”上添加@ConstructorProperties,但无济于事。


我的不可变表单/bean 对象:

public class ImmutableObj {
    private final Integer id;
    private final String name;

    // no arg constructor
    // spring calls this one when resolving request params
    public ImmutableObj() {
        this(null, null);
    }

    // required args constructor
    // I want spring to call this one when resolving request params
    @ConstructorProperies({"id", "name"})
    public ImmutableObj(Integer id, String name) {
        this.id = id;
        this.name = name;
    }

    public Integer getId() {
        return id;
    }

    public String getName() {
        return name;
    }
}

还有我的控制器:

@Controller
public class MyController {
    @GetMapping("myStuff")
    public String getMyStuff(ImmutableObj requestParams) {
        // here the value of request params
        // has nulls due to no arg constructor being called 
        return "someStuff";
    }
}

调用“/myStuff?id=123&name=hello”时

预期 - requestParams.getId()=123, requestParams.getName()=hello

实际 - requestParams.getId()=null, requestParams.getName()=null


更新!!!!!!!!!!!!

删除无参数构造函数后,我现在遇到了合成问题:

public class ImmutableObj {
    private final SomeOtherObj someOtherObj;

    public ImmutableObj(SomeOtherObj obj) {
        someOtherObj = obj;
    }
}

public class SomeOtherObj {
    private final Integer id;
    private final String name;

    public SomeOtherObj(Integer id, String name) {
        this.id = id;
        this.name = name;
    }
}

还有弹簧投掷:

Could not instantiate property type [SomeOtherObj] to auto-grow nested property path; nested exception is java.lang.NoSuchMethodException: SomeOtherObj.<init>()

【问题讨论】:

  • 你为什么有默认构造函数?
  • 我有一个用例,如果找不到,我们需要返回一个“空”对象。现在我想起来了,我可以使用像ImmutableObject.empty() 这样的静态方法,doooooh。无论哪种方式,我都想知道是否有办法直接让 spring 选择一个 required-args 构造函数,而不是 no arg 构造函数?
  • @akk202 出了什么问题? (你删除了评论)
  • @AndrewTobilko 我在我原来的问题中更新了它。我没有删除任何 cmets。
  • 使用数据绑定时不能这样做。 Spring 需要根据 java bean 规范的属性或使用直接字段访问。它不会使用 all args 构造函数将来自 web 的参数绑定到表单,它将始终使用默认的 no-args 构造函数。事实上,这是将对象用作表单对象的要求。 (不适用于在应用程序上下文中用作 bean 的类)。

标签: java spring spring-mvc spring-form


【解决方案1】:

Spring 总是调用无参数构造函数,而不是初始化值。

当 Spring 看到类有多个构造函数时,它会去搜索一个无参数的构造函数。如果 Spring 没有找到,就会抛出异常。

当 Spring 看到类只有一个构造函数时,无论它有多少参数,它都会接受它。

如何确保 spring 只调用所需的参数构造函数?

唯一的方法是在类中只有一个构造函数。为了让 Spring 更加明确。

顺便说一句,

  1. 如果字段名称对应于 URL 参数名称,则不需要 @ConstructorProperies({"id", "name"})。 Spring 可以解决这个问题。

  2. public ImmutableObj() {
        this(null, null);
    }
    

不是一个好主意。 ImmutableObj.empty() 会更好。

作为奖励,如果您想了解幕后发生的事情,这就是我所说的 sn-p

if (ctor == null) {
  Constructor<?>[] ctors = clazz.getConstructors();
  if (ctors.length == 1) {
    ctor = ctors[0];
  } else {
    try {
      ctor = clazz.getDeclaredConstructor();
    } catch (NoSuchMethodException var10) {
      throw new IllegalStateException("No primary or default constructor found for " + clazz, var10);
    }
  }
}

【讨论】:

  • 非常感谢您的洞察力。谢谢!。我现在正在尝试解决与组合(包含表单的表单)相关的问题。而这次 spring 抱怨没有找到默认构造函数? (请参阅我对原始问题的更新)
  • 如果你想自动传递构造函数参数,你应该在Spring上下文中初始化bean,并在调用时需要初始化参数的构造函数上放置@Autowired注解。如果 Spring 找不到 bean 来初始化构造函数参数,Spring 不知道如何调用该构造函数。
  • 这仅适用于上下文中定义的 bean。从表单到对象进行数据绑定时,它将不起作用。
  • @M.Deinum 谢谢!会记住这一点。我已经求助于仅用于弹簧形式的 DTO 并将其转换为不可变的以满足我的需要。以为我会避免它,但看起来作曲没有其他出路
  • @SachithDickwella 我不使用春豆。只是表单(请求参数 -> 装饰表单)
猜你喜欢
  • 2016-01-02
  • 2011-09-05
  • 2016-09-02
  • 1970-01-01
  • 2014-06-30
  • 2020-09-26
  • 1970-01-01
  • 2019-02-26
  • 2013-06-01
相关资源
最近更新 更多