zoukankan      html  css  js  c++  java
  • 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);
        }
    

    由于时间仓促这一块没有去仔细思考这种改法有没有问题或者有没有更好的改法,后续有时间会对本文进行更新。

  • 相关阅读:
    每天玩转3分钟 MyBatis-Plus
    每天玩转3分钟 MyBatis-Plus
    每天玩转3分钟 MyBatis-Plus
    git仓库管理
    【SpringCloud之pigx框架学习之路 】2.部署环境
    【SpringCloud之pigx框架学习之路 】1.基础环境安装
    Ubuntu 14.04 安装mysql
    Netflix是什么,与Spring Cloud有什么关系
    现学现用-我的第三个小小小私活
    申请微信小游戏账号
  • 原文地址:https://www.cnblogs.com/CodingJacob/p/12341426.html
Copyright © 2011-2022 走看看