Unable to find a constructor that takes a String param or a valueOf() or fromString() method
Unable to find a constructor that takes a String param or a valueOf() or fromString() method
最近在做服务的dubbo-rest改造,在启动服务的时候遇到这个错。
2020-02-21 14:15:51,433 [main] ERROR org.springframework.boot.SpringApplication - Application startup failed
java.lang.RuntimeException: RESTEASY003875: Unable to find a constructor that takes a String param or a valueOf() or fromString() method for javax.ws.rs.QueryParam("roleList") on java.util.List com.xxx.uic.entity.req.UserRoleReq.roleList for basetype: com.xxx.uic.entity.req.RoleReq
	at org.jboss.resteasy.core.StringParameterInjector.initialize(StringParameterInjector.java:220)
	at org.jboss.resteasy.core.StringParameterInjector.<init>(StringParameterInjector.java:64)
	at org.jboss.resteasy.core.QueryParamInjector.<init>(QueryParamInjector.java:30)
	at org.jboss.resteasy.core.InjectorFactoryImpl.createParameterExtractor(InjectorFactoryImpl.java:165)
	at org.jboss.resteasy.core.PropertyInjectorImpl.getParameterExtractor(PropertyInjectorImpl.java:118)
	at org.jboss.resteasy.core.PropertyInjectorImpl.populateMap(PropertyInjectorImpl.java:66)
	at org.jboss.resteasy.core.PropertyInjectorImpl.<init>(PropertyInjectorImpl.java:54)
	at org.jboss.resteasy.core.InjectorFactoryImpl.createPropertyInjector(InjectorFactoryImpl.java:65)
	at org.jboss.resteasy.core.FormInjector.<init>(FormInjector.java:37)
	at org.jboss.resteasy.core.InjectorFactoryImpl.createParameterExtractor(InjectorFactoryImpl.java:119)
	at org.jboss.resteasy.core.MethodInjectorImpl.<init>(MethodInjectorImpl.java:44)
	at org.jboss.resteasy.core.InjectorFactoryImpl.createMethodInjector(InjectorFactoryImpl.java:77)
	at org.jboss.resteasy.core.ResourceMethodInvoker.<init>(ResourceMethodInvoker.java:99)
	at org.jboss.resteasy.core.ResourceMethodRegistry.processMethod(ResourceMethodRegistry.java:281)
	at org.jboss.resteasy.core.ResourceMethodRegistry.register(ResourceMethodRegistry.java:252)
	at org.jboss.resteasy.core.ResourceMethodRegistry.addResourceFactory(ResourceMethodRegistry.java:222)
	at org.jboss.resteasy.core.ResourceMethodRegistry.addResourceFactory(ResourceMethodRegistry.java:194)
	at org.jboss.resteasy.core.ResourceMethodRegistry.addResourceFactory(ResourceMethodRegistry.java:180)
	at com.alibaba.dubbo.rpc.protocol.rest.BaseRestServer.deploy(BaseRestServer.java:46)
	....
大意就是我的@QueryParam注解下的参数没有使用String参数的构造方法,也没有对应的valueOf()和fromString(),所以这里是没法反序列化的。
    @QueryParam("roleList")
    List<RoleReq> roleList;
如果深究这里的原因,需要查看resteasy里面的部分源码。
//String参数注入器 初始化方法
protected void initialize(Class type, Type genericType, String paramName, Class paramType, String defaultValue, AccessibleObject target, Annotation[] annotations, ResteasyProviderFactory factory)
   {
      this.type = type;
      this.paramName = paramName;
      this.paramType = paramType;
      this.defaultValue = defaultValue;
      this.target = target;
      baseType = type;
      baseGenericType = genericType;
  		//对集合类型进行判断
      if (type.isArray()) baseType = type.getComponentType();
      if (List.class.isAssignableFrom(type))
      {
         isCollection = true;
         collectionType = ArrayList.class;
      }
      else if (SortedSet.class.isAssignableFrom(type))
      {
         isCollection = true;
         collectionType = TreeSet.class;
      }
      else if (Set.class.isAssignableFrom(type))
      {
         isCollection = true;
         collectionType = HashSet.class;
      }
      if (isCollection)
      {
         //如果是集合类型,取集合内成员的类型
         if (genericType != null && genericType instanceof ParameterizedType)
         {
            ParameterizedType zType = (ParameterizedType) genericType;
            baseType = Types.getRawType(zType.getActualTypeArguments()[0]);
            baseGenericType = zType.getActualTypeArguments()[0];
         }
         else
         {
            baseType = String.class;
            baseGenericType = null;
         }
      }
      if (!baseType.isPrimitive())
      {
         //如果注入对象类型为非基础类型,尝试拿到参数的转换器
         paramConverter = factory.getParamConverter(baseType, baseGenericType, annotations);
         if (paramConverter != null) return;
				 //尝试获取解析器
         unmarshaller = factory.createStringParameterUnmarshaller(baseType);
         if (unmarshaller != null)
         {
            unmarshaller.setAnnotations(annotations);
            return;
         }
         for (Annotation annotation : annotations)
         {
            StringParameterUnmarshallerBinder binder = annotation.annotationType().getAnnotation(StringParameterUnmarshallerBinder.class);
            if (binder != null)
            {
               try
               {
                  unmarshaller = binder.value().newInstance();
               }
               catch (InstantiationException e)
               {
                  throw new RuntimeException(e.getCause());
               }
               catch (IllegalAccessException e)
               {
                  throw new RuntimeException(e);
               }
               factory.injectProperties(unmarshaller);
               unmarshaller.setAnnotations(annotations);
               return;
            }
         }
				 //尝试获取String的转换器
         converter = factory.getStringConverter(baseType);
         if (converter != null) return;
         if (paramType.equals(HeaderParam.class))
         {
            delegate = factory.getHeaderDelegate(baseType);
            if (delegate != null) return;
         }
         try
         {
            constructor = baseType.getConstructor(String.class);
            if (!Modifier.isPublic(constructor.getModifiers())) constructor = null;
         }
         catch (NoSuchMethodException ignored)
         {
         }
         if (constructor == null)
         {
            try
            {
               // this is for JAXB generated enums.
               Method fromValue = baseType.getDeclaredMethod("fromValue", String.class);
               if (Modifier.isPublic(fromValue.getModifiers()))
               {
                  for (Annotation ann : baseType.getAnnotations())
                  {
                     if (ann.annotationType().getName().equals("javax.xml.bind.annotation.XmlEnum"))
                     {
                        valueOf = fromValue;
                     }
                  }
               }
            }
            catch (NoSuchMethodException e)
            {
            }
           //以上转换方式都没有,尝试使用方法名匹配,使用fromString和valueOf去匹配方法
            if (valueOf == null)
            {
               Method fromString = null;
               try
               {
                  fromString = baseType.getDeclaredMethod("fromString", String.class);
                  if (Modifier.isStatic(fromString.getModifiers()) == false) fromString = null;
               }
               catch (NoSuchMethodException ignored)
               {
               }
               try
               {
                  valueOf = baseType.getDeclaredMethod("valueOf", String.class);
                  if (Modifier.isStatic(valueOf.getModifiers()) == false) valueOf = null;
               }
               catch (NoSuchMethodException ignored)
               {
               }
               // If enum use fromString if it exists: as defined in JAX-RS spec
               if (baseType.isEnum())
               {
                  if (fromString != null)
                  {
                     valueOf = fromString;
                  }
               }
               else if (valueOf == null)
               {
                  valueOf = fromString;
               }
               if (valueOf == null)
               {
                 //如果还是没有则抛出上面的异常
                  throw new
                 RuntimeException(Messages.MESSAGES.unableToFindConstructor(getParamSignature(), target, baseType.getName()));
               }
            }
         }
      }
   }
为了解决这个问题,我对RoleReq类增加了valueof(String)的方法来实现String反序列化成我需要的bean。
    public static RoleReq valueOf(String string){
        return JSONObject.parseObject(string,RoleReq.class);
    }
由于时间仓促这一块没有去仔细思考这种改法有没有问题或者有没有更好的改法,后续有时间会对本文进行更新。
Unable to find a constructor that takes a String param or a valueOf() or fromString() method的更多相关文章
- C# "error CS1729: 'XXClass' does not contain a constructor that takes 0 arguments"的解决方案
		
出现这种错误的原因时,没有在子类的构造函数中指出仅有带参构造函数的父类的构造参数. 具体来讲就是: 当子类要重用父类的构造函数时, C# 语法通常会在子类构造函数后面调用 : base( para_t ...
 - Unable to locate appropriate constructor on class异常
		
一般出现Unable to locate appropriate constructor on class这个异常,都是实体类的带参数的构造方法和使用查询语句出现偏差,两个地方的代码如下: 一般都是第 ...
 - 【Hibernate】Unable to locate appropriate constructor on class原因分析
		
通常我们喜欢将hql查询结果封装到POJO对象syntax:select new POJO(id,name) from POJO ; 这种封装需要POJO类提供对应构造器,POJO(id,name)构 ...
 - Unable to find a constructor to use for type System.Security.Claims.Claim. A class should either have a default constructor
		
Newtonsoft.Json DeserializeObject 反序列化 IdentityServer4.Models Cliecnt 错误: Newtonsoft.Json.JsonSeria ...
 - Unable to locate appropriate constructor on class报错
		
在项目开发中,使用Hibernate里的JPA criteria查询,但是在写完之后使用时,会报错:Unable to locate appropriate constructor on class, ...
 - Base class does not contain a constructor that takes '0' argument
		
刚刚在写一段直播室网站中的一段程序遇,突然遇到一个错误,如下 'TVLLKBLL.BaseClass' does not contain a constructor that takes 0 argu ...
 - Hibernate异常:Unable to locate appropriate constructor on class
		
异常信息:org.hibernate.hql.ast.QuerySyntaxException: Unable to locate appropriate constructor on class o ...
 - 出现Unable to locate appropriate constructor on class 错误可能的原因
		
1)参数构造器的参数类型是否正确2)参数构造器的顺序和hql中的顺序是否一致3)参数构造器的参数个数是否和hql中的个数一致4)参数构造器的参数类型是否TimeStamp
 - C#  does not contain a constructor that takes no parameter
		
C# 中子类要重用父类的构造函数时, 一般会在子类构造函数后面调用 : base(paratype, para). 如果父类有一个參数个数为1的构造函数, 没有 0 參构造函数. 子类想要重用这个构造 ...
 
随机推荐
- python动态柱状图图表可视化:历年软科中国大学排行
			
本来想参照:https://mp.weixin.qq.com/s/e7Wd7aEatcLFGgJUDkg-EQ搞一个往年编程语言动态图的,奈何找不到数据,有数据来源的欢迎在评论区留言. 这里找到了一个 ...
 - 技术干货丨卷积神经网络之LeNet-5迁移实践案例
			
摘要:LeNet-5是Yann LeCun在1998年设计的用于手写数字识别的卷积神经网络,当年美国大多数银行就是用它来识别支票上面的手写数字的,它是早期卷积神经网络中最有代表性的实验系统之一.可以说 ...
 - Docker(五)Docker镜像讲解
			
Docker镜像讲解 镜像概念 镜像是一种轻量级.可执行的独立软件包,用来打包软件运行环境和基于运行环境开发的软件,它包含运行某个软件所需的所有内容,包括代码.运行时.库.环境变量和配置文件 Dock ...
 - Spring IoC bean 的创建(上)
			
前言 本系列全部基于 Spring 5.2.2.BUILD-SNAPSHOT 版本.因为 Spring 整个体系太过于庞大,所以只会进行关键部分的源码解析. 本篇文章主要介绍 Spring IoC 容 ...
 - 入门大数据---通过Flume、Sqoop分析日志
			
一.Flume安装 参考:Flume 简介及基本使用 二.Sqoop安装 参考:Sqoop简介与安装 三.Flume和Sqoop结合使用案例 日志分析系统整体架构图: 3.1配置nginx环境 请参考 ...
 - Redis高级特性
			
redis的事务(transaction) 转载:https://blog.csdn.net/fmwind/article/details/78065236 redis中的事务是一组命令的集合.事务同 ...
 - Tensorflow与Keras自适应使用显存
			
Tensorflow支持基于cuda内核与cudnn的GPU加速,Keras出现较晚,为Tensorflow的高层框架,由于Keras使用的方便性与很好的延展性,之后更是作为Tensorflow的官方 ...
 - python设计模式之策略模式
			
每次看到项目中存在大量的if else代码时,都会心生一丝不安全感. 特别是产品给的需求需要添加或者更改一种if条件时,生怕会因为自己的疏忽而使代码天崩地裂,哈哈,本文的目的就是来解决这种不安全感的, ...
 - 《UNIX环境高级编程》(APUE) 笔记第七章 - 进程环境
			
7 - 进程环境 Github 地址 1. main 函数 C 程序总是从 main 函数 开始执行: int main(int argc, char *argv[]); \(argc\) 为命令行参 ...
 - 注册中心(Eureka/Consul)
			
基于SpringBoot1.5.4与SpringCloud(Dalston.SR2)的SpringCloud学习博客,转载请标明出处,O(∩_∩)O谢谢 - Spring Cloud简介 Spring ...