我正在使用apache CXF。
以下API用于发布联系人。
@POST
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
ResponseResult create(@Context HttpHeaders httpHeaders, @Context Request request, @Context UriInfo uriInfo,
UserContact contact) throws MDMException;
此处UserContact类包含有关用户的联系信息,该用户在正文中作为JSON传递。
我需要对此UserContact对象进行一些业务验证。但是我不喜欢在一个类中包含太多的验证代码。
我想做类似以下的事情。但我面临着泛型的问题。
interface Rule<S>
{
void applyRule(S s)throws Exception;
}
interface Validatable
{
void validate() throws Exception;
}
public class MyValidator
{
private HashMap<? extends Rule ,?> map = new HashMap<>();
public void validate() throws Exception
{
for(Rule rule : map.keySet())
{
rule.applyRule(map.get(rule));
}
}
public <S> void addRule(Rule<S> rule, S data)
{
this.map.put(rule, data);
}
}
class EMailValidationRule implements Rule<String>
{
private static final Pattern emailPattern = Pattern.compile("email-regex");
public void applyRule(String s) throws Exception
{
if(!emailPattern.matcher(s).matches())
throw new Exception("Not a valid EMail");
}
}
因此UserContact必须执行以下操作以进行验证。这使代码保持紧凑(IMO)。
class UserContact implements Validatable
{
// some
// code
// related to User Contact
public void validate() throws Exception
{
MyValidator validator = new MyValidator();
validator.addRule(new EMailValidationRule(), "developer@stackoverflow.com");
validator.addRule(new PhoneValidationRule(), "+1234567890");
validator.validate();
}
}
我一直收到如下错误:
HashMap类型中的put(捕获#5-of?extends Rule,capture#6-of?)不适用 对于参数(规则,S)
上述设计也适合做验证吗?
答案 0 :(得分:2)
问题在于,尽管您的封装确保了它,但编译器无法确定检索到的Rule<...>
是否具有与检索到的数据相同类型的类型参数。
还存在无法使用Rule<T>
子类型的数据插入T
的问题。如果您有Rule<S> rule, S data
,那么类型必须完全匹配。虽然Rule<S>
可以处理S
的子类型,但很好。
虽然MyValidator
是一个很酷的小班,但我真的没有意识到这一点。特别是因为每次拨打validate
时都会创建一个新的。它也很难缓存,因为规则是静态的(对于每个类的实例都是相同的),数据来自单个实例(我假设)。
您也可以这样做:
class UserContact implements Validatable
{
// some
// code
// related to User Contact
// 1 rule instance for the entire class, not a new one per call to 'validate'
private static EMailValidationRule emailRule = new EmailValidationRule();
private static PhoneValidationRule phoneRule = new PhoneValidationRule();
public void validate() throws Exception
{
emailRule.applyRule("developer@stackoverflow.com");
phoneRule.applyRule("+1234567890");
}
}
从不如此,这是MyValidator
的工作版本:
class MyValidator {
private Map<Rule<?>, RuleNode<?>> map = new HashMap<>();
public void validate() throws Exception {
for(RuleNode<?> node : map.values())
node.apply();
}
public <T, D extends T> void addRule(Rule<T> rule, D data) {
@SuppressWarnings("unchecked") // unchecked, but safe due to encapsulation
RuleNode<T> r = (RuleNode<T>) map.get(rule);
if(r == null) {
r = new RuleNode<T>(rule);
map.put(rule, r);
}
r.add(data);
}
private static class RuleNode<T> { // Maintains that the rule and data are compatible
private final Rule<T> rule;
private final List<T> list = new ArrayList<>();
public RuleNode(Rule<T> rule) {
this.rule = rule;
}
public void add(T data) {
list.add(data);
}
public void apply() throws Exception {
for(T data : list)
rule.applyRule(data);
}
}
}
答案 1 :(得分:2)
您只需要制作MyValidator
类
泛型类使用以下格式定义:
class name<T1, T2, ..., Tn> { /* ... */ }
使用泛型定义类,您将指定要在类中使用的类型,在您的情况下<R extends Rule<S> ,S>
class MyValidator<R extends Rule<S> ,S>{
private HashMap<R ,S> map = new HashMap<>();
public void validate() throws Exception{
for(Rule<S> rule : map.keySet()){
rule.applyRule(map.get(rule));
}
}
public void addRule(R rule, S data){
this.map.put(rule, data);
}
}
完成后,您只需构建所需类型的MyValidator
:
MyValidator<Rule<String>, String> validator = new MyValidator<>();
最后添加与验证器类型匹配的规则:
validator.addRule(new EMailValidationRule(), "developer@stackoverflow.com");
例如,添加一个您的UserContact
看起来像的电话验证器:
class PhoneValidationRule implements Rule<String>{
private static final Pattern phonePattern = Pattern.compile("phone-regex");
public void applyRule(String s) throws Exception{
if(!phonePattern.matcher(s).matches())
throw new Exception("Not a valid phone");
}
}
class UserContact implements Validatable{
public void validate() throws Exception{
MyValidator<Rule<String>, String> validator = new MyValidator<>();
validator.addRule(new EMailValidationRule(), "developer@stackoverflow.com");
validator.addRule(new PhoneValidationRule(), "developer@stackoverflow.com");
validator.validate();
}
}