[英]Loading Java Builder Object from Yaml file
我使用Builder Pattern创建了一个Bean类,并且在从yaml文件创建对象时遇到了问题。
这是一个示例类(实际类很大,如果你想用一个例子来回答,这只是一个摘录):
public class ClientBuilder {
private final String firstName;
private final String lastName;
private final String displayName;
private ClientBuilder(Builder builder) {
firstName = builder.firstName;
lastName = builder.lastName;
displayName = builder.displayName;
}
public static class Builder {
private final String displayName; // Mandatory Attribute
public Builder( String displayName ) {
this.displayName = displayName;
}
private String firstName;
private String lastName;
public Builder setFirstName(String firstName) {
this.firstName = firstName;
return this;
}
public Builder setLastName(String lastName) {
this.lastName = lastName;
return this;
}
public ClientBuilder build() {
return new ClientBuilder(this);
}
}
@Override
public String toString() {
StringBuffer sbf = new StringBuffer();
sbf.append("New Company Object: \n");
sbf.append("firstName : " + this.firstName + "\n");
sbf.append("lastName : " + this.lastName + "\n");
sbf.append("displayName : " + this.displayName + "\n");
return sbf.toString();
}
}
我使用snakeyaml加载文件,但任何yaml api都可以。 由于displayName
是必需的参数,我想在创建实例时传递该值。 其他参数可以在创建对象时传递,但我希望通过yaml文件加载它们。
如果我使用java bean,我可以加载yaml文件。 有没有办法实例化构建器对象?
我试过了:
InputStream input = new FileInputStream(new File("src/main/resources/client.yaml"));
Yaml yaml = new Yaml();
Builder builder = new Builder("Display Name");
builder = (Builder) yaml.loadAs(input, ClientBuilder.Builder.class);
ClientBuilder client = builder.build();
System.out.println(client.toString());
但我得到以下错误:
Exception in thread "main" Can't construct a java object for tag:yaml.org,2002:com.xxx.xxx.xxx.ClientBuilder$Builder; exception=java.lang.NoSuchMethodException: com.xxx.xxx.xxx.ClientBuilder$Builder.<init>()
in 'reader', line 2, column 1:
firstName: "Jaypal"
SnakeYaml是一个非常强大的库,它支持基于构造函数注入创建实例。
/**
* create JavaBean
*/
public void testGetBeanAssumeClass() {
String data = "--- !!org.yaml.snakeyaml.constructor.Person\nfirstName: Andrey\nage: 99";
Object obj = construct(data);
assertNotNull(obj);
assertTrue("Unexpected: " + obj.getClass().toString(), obj instanceof Person);
Person person = (Person) obj;
assertEquals("Andrey", person.getFirstName());
assertNull(person.getLastName());
assertEquals(99, person.getAge().intValue());
}
/**
* create instance using constructor arguments
*/
public void testGetConstructorBean() {
String data = "--- !!org.yaml.snakeyaml.constructor.Person [ Andrey, Somov, 99 ]";
Object obj = construct(data);
assertNotNull(obj);
assertTrue(obj.getClass().toString(), obj instanceof Person);
Person person = (Person) obj;
assertEquals("Andrey", person.getFirstName());
assertEquals("Somov", person.getLastName());
assertEquals(99, person.getAge().intValue());
}
可在此处查看Junit代码示例 。 所以你的代码仍然很好。 您可能需要使用正确的格式更改yaml内容。 一旦完成,你就完成了。
正如您可能已经想到的那样,例外情况是在Builder
没有无参数构造函数。
你可以做的是为Builder
提供no-arg构造函数,并为其添加displayName
相应setter和getter。 如果未设置displayName
(或为其提供默认值build()
则只需在build()
抛出异常。 异常可以是运行时异常,也可以将其清除并添加显式throws
。
虽然它不是最漂亮的解决方案,但应该可以正常工作。 在没有强制参数的情况下创建Builder
的事实应该无关紧要,因为需要正确构造ClientBuilder
(因为工厂/构建器用于确保构建的任何实例的每个实例都是正确的)。
我目前无法访问任何针对Java的yaml解析工具,但如果有任何方法可以改进我的答案,请告诉我 - 我很乐意这样做。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.