java.lang.IllegalArgumentException: Tuple created with wrong number of fields. Expected 1 fields but

本文详细记录了从Storm 0.9.8升级到1.1.1版本过程中遇到的启动错误及其解决办法。错误原因是Scheme接口实现中deserialize方法参数类型由byte[]变为ByteBuffer。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

由于以前使用的storm是0.9.8版本的,新公司使用的版本是1.1.1版本的,在本地模式启动storm的时候报错如下:

8747 [Thread-32-spout-executor[4 4]] ERROR o.a.s.util - Async loop died!
java.lang.IllegalArgumentException: Tuple created with wrong number of fields. Expected 1 fields but got 2 fields
at org.apache.storm.tuple.TupleImpl.<init>(TupleImpl.java:58) ~[storm-core-1.1.1.jar:1.1.1]
at org.apache.storm.daemon.executor$fn__4962$fn__4977$send_spout_msg__4983.invoke(executor.clj:570) ~[storm-core-1.1.1.jar:1.1.1]
at org.apache.storm.daemon.executor$fn__4962$fn$reify__4993.emit(executor.clj:611) ~[storm-core-1.1.1.jar:1.1.1]
at org.apache.storm.spout.SpoutOutputCollector.emit(SpoutOutputCollector.java:50) ~[storm-core-1.1.1.jar:1.1.1]
at org.apache.storm.spout.SpoutOutputCollector.emit(SpoutOutputCollector.java:65) ~[storm-core-1.1.1.jar:1.1.1]
at org.apache.storm.kafka.PartitionManager.next(PartitionManager.java:204) ~[storm-kafka-1.1.1.jar:1.1.1]
at org.apache.storm.kafka.KafkaSpout.nextTuple(KafkaSpout.java:136) ~[storm-kafka-1.1.1.jar:1.1.1]
at org.apache.storm.daemon.executor$fn__4962$fn__4977$fn__5008.invoke(executor.clj:646) ~[storm-core-1.1.1.jar:1.1.1]
at org.apache.storm.util$async_loop$fn__557.invoke(util.clj:484) [storm-core-1.1.1.jar:1.1.1]
at clojure.lang.AFn.run(AFn.java:22) [clojure-1.7.0.jar:?]
at java.lang.Thread.run(Thread.java:748) [?:1.8.0_131]
8748 [Thread-32-spout-executor[4 4]] ERROR o.a.s.d.executor - 
java.lang.IllegalArgumentException: Tuple created with wrong number of fields. Expected 1 fields but got 2 fields
at org.apache.storm.tuple.TupleImpl.<init>(TupleImpl.java:58) ~[storm-core-1.1.1.jar:1.1.1]
at org.apache.storm.daemon.executor$fn__4962$fn__4977$send_spout_msg__4983.invoke(executor.clj:570) ~[storm-core-1.1.1.jar:1.1.1]
at org.apache.storm.daemon.executor$fn__4962$fn$reify__4993.emit(executor.clj:611) ~[storm-core-1.1.1.jar:1.1.1]
at org.apache.storm.spout.SpoutOutputCollector.emit(SpoutOutputCollector.java:50) ~[storm-core-1.1.1.jar:1.1.1]
at org.apache.storm.spout.SpoutOutputCollector.emit(SpoutOutputCollector.java:65) ~[storm-core-1.1.1.jar:1.1.1]
at org.apache.storm.kafka.PartitionManager.next(PartitionManager.java:204) ~[storm-kafka-1.1.1.jar:1.1.1]
at org.apache.storm.kafka.KafkaSpout.nextTuple(KafkaSpout.java:136) ~[storm-kafka-1.1.1.jar:1.1.1]
at org.apache.storm.daemon.executor$fn__4962$fn__4977$fn__5008.invoke(executor.clj:646) ~[storm-core-1.1.1.jar:1.1.1]
at org.apache.storm.util$async_loop$fn__557.invoke(util.clj:484) [storm-core-1.1.1.jar:1.1.1]
at clojure.lang.AFn.run(AFn.java:22) [clojure-1.7.0.jar:?]
at java.lang.Thread.run(Thread.java:748) [?:1.8.0_131]
8832 [Thread-32-spout-executor[4 4]] ERROR o.a.s.util - Halting process: ("Worker died")
java.lang.RuntimeException: ("Worker died")
at org.apache.storm.util$exit_process_BANG_.doInvoke(util.clj:341) [storm-core-1.1.1.jar:1.1.1]
at clojure.lang.RestFn.invoke(RestFn.java:423) [clojure-1.7.0.jar:?]
at org.apache.storm.daemon.worker$fn__5628$fn__5629.invoke(worker.clj:759) [storm-core-1.1.1.jar:1.1.1]
at org.apache.storm.daemon.executor$mk_executor_data$fn__4848$fn__4849.invoke(executor.clj:276) [storm-core-1.1.1.jar:1.1.1]
at org.apache.storm.util$async_loop$fn__557.invoke(util.clj:494) [storm-core-1.1.1.jar:1.1.1]
at clojure.lang.AFn.run(AFn.java:22) [clojure-1.7.0.jar:?]
at java.lang.Thread.run(Thread.java:748) [?:1.8.0_131]



扯一下:这个错误弄了一天才弄好,

查资料有人说field的数量和 Value的数量不一致,但是我的明明一致????

public void declareOutputFields(OutputFieldsDeclarer declarer) {

    declarer.declare(new Fields("end")
    );

@Override
public void execute(Tuple input) {
    Room room = (Room)input.getValueByField("room");
    System.out.println(room);
    collector.emit(new Values("Aaaa","aaaaaa"));
}

后来仔细研究发现:问题出现在Scheme上面,在storm0.9.8的时候实现Scheme接口的方法
deserialize的参数为byte[] ,而storm1.1.1的参数为ByteBuffer
形式如下:
package logAnalyze.storm.spout;

import backtype.storm.spout.Scheme;
import backtype.storm.tuple.Fields;
import backtype.storm.tuple.Values;

import java.util.List;

public class StringScheme implements Scheme {
    public List<Object> deserialize(byte[] bytes) {
        try {
            return new Values(new String(bytes));
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    public Fields getOutputFields() {
        return new Fields("line");
    }
}


所以,只需要吧implements Scheme的类进行重写就行,形式如下:
package com.qk365.report.storm.spout;

import org.apache.storm.spout.Scheme;
import org.apache.storm.tuple.Fields;
import org.apache.storm.tuple.Values;


import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.util.List;

public class StringScheme implements Scheme {
    public List<Object> deserialize(ByteBuffer bytes) {
        try {
            return new Values(getStringByByteBuffer(bytes));
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    public Fields getOutputFields() {
        return new Fields("line");
    }

    private String getStringByByteBuffer(ByteBuffer buffer) {
        Charset charset = null;
        CharsetDecoder decoder = null;
        CharBuffer charBuffer = null;
        try {
            charset = Charset.forName("UTF-8");
            decoder = charset.newDecoder();
            charBuffer = decoder.decode(buffer.asReadOnlyBuffer());
            return charBuffer.toString();
        } catch (Exception e) {
            return "";
        }
    }
}



最后不要忘了在main方法里面进行设置
package com.qk365.report.storm;


import com.qk365.report.storm.bolt.ParseRecordBolt;
import com.qk365.report.storm.spout.StringScheme;
import org.apache.storm.Config;
import org.apache.storm.LocalCluster;
import org.apache.storm.StormSubmitter;
import org.apache.storm.kafka.BrokerHosts;
import org.apache.storm.kafka.KafkaSpout;
import org.apache.storm.kafka.SpoutConfig;
import org.apache.storm.kafka.ZkHosts;
import org.apache.storm.spout.SchemeAsMultiScheme;
import org.apache.storm.topology.TopologyBuilder;

import java.util.HashMap;
import java.util.Map;


public class KafkaAndStormTopologyMain {
    public static void main(String[] args) throws Exception{
        //配置zookeeper 主机:端口号
        BrokerHosts brokerHosts =new ZkHosts("qkt-datacenter1:2181,qkt-datacenter2:2181,qkt-datacenter3:2181");
        //接收消息队列的主题
        String topic="orderMq_room";
        //zookeeper设置文件中的配置,如果zookeeper配置文件中设置为主机名:端口号 ,该项为空
        String zkRoot="/orderMq";
        //任意
        String spoutId="input";
        SpoutConfig spoutConfig=new SpoutConfig(brokerHosts, topic, zkRoot, spoutId);
        //设置如何处理kafka消息队列输入流
        spoutConfig.scheme=new SchemeAsMultiScheme(new StringScheme());
        Config conf=new Config();
        //不输出调试信息
        conf.setDebug(true);
        //设置一个spout task中处于pending状态的最大的tuples数量
        conf.put(Config.TOPOLOGY_MAX_SPOUT_PENDING, 1);
        Map<String, String> map=new HashMap<String,String>();
        // 配置Kafka broker地址
        map.put("metadata.broker.list", "qkt-datacenter3:9092,qkt-datacenter5:9092,qkt-datacenter6:9092");
        // serializer.class为消息的序列化类
        map.put("serializer.class", "kafka.serializer.StringEncoder");
        conf.put("kafka.broker.properties", map);
        // 配置KafkaBolt生成的topic
        conf.put("topic", "kafkaSpout");

        TopologyBuilder builder = new TopologyBuilder();
        builder.setSpout("spout", new KafkaSpout(spoutConfig),1);

        builder.setBolt("bolt1", new ParseRecordBolt(),1).setNumTasks(1).shuffleGrouping("spout");
      //  builder.setBolt("bolt2", new HandleRecordBolt(),1).setNumTasks(1).shuffleGrouping("bolt1");
        conf.setNumWorkers(2);

        //3、提交任务  -----两种模式 本地模式和集群模式
        if (args.length>0) {
            StormSubmitter.submitTopology(args[0], conf, builder.createTopology());
        }else {
            conf.setMaxTaskParallelism(3);
            LocalCluster localCluster = new LocalCluster();
            localCluster.submitTopology("test", conf, builder.createTopology());
        }
    }
}


### 导致 `java.lang.IllegalArgumentException: wrong number of arguments` 的原因 该异常通常发生在 Java 反射机制中,当尝试通过反射调用方法或构造函数时传递的参数数量与目标方法或构造函数签名中的参数数量不匹配时会抛出此异常[^1]。具体来说: - 如果使用 `Method.invoke()` 或 `Constructor.newInstance()` 调用某个方法或构造函数时,实际传递的参数数量少于或多于预期的数量,则会触发此异常。 - 参数类型的不一致也可能引发类似的错误。 #### 场景分析 在某些情况下,开发者可能会误以为可以将数组作为单个参数传递给只接受单一参数的方法,但实际上如果没有正确处理类型转换,也会导致此类问题。例如,在引用案例中提到的一个典型问题是:如果一个方法期望接收的是字符串数组 (`String[]`) 类型的单个参数,而直接传递了一个未封装的对象列表,则可能导致参数被误解为多个独立参数而非整体数组[^3]。 ### 解决方案 为了有效解决这个问题,可以从以下几个方面入手: 1. **确认方法签名** 需要仔细核对所操作的目标类及其成员方法或者构造器的确切定义,确保了解其所需的具体参数数目以及每种参数的数据类型[^2]。 2. **调整参数传递方式** 当涉及复杂数据结构如数组时,应特别注意如何适当地准备这些输入值以便它们能够按照预期的方式被解释。比如对于期待获得整个集合形式参数的情况,应该先将其打包成合适的容器实例再提交给反射API去执行调用动作[^3]。 以下是基于上述原则的一个修正后的代码片段展示: ```java public class CorrectReflectionExample { public static void main(String[] args) throws Exception{ Student student = new Student(); Class<?> clazz = Class.forName("CorrectReflectionExample$Student"); Method method = clazz.getMethod("printScores", String[].class); String[] scores = {"A+", "B-", "C"}; // 将scores数组作为一个单独的对象来传递 method.invoke(student, (Object)scores); } private static class Student { public void printScores(String... scores){ System.out.println(Arrays.toString(scores)); } } } ``` 在这个例子当中,我们明确地告诉JVM我们要把`scores`当作是一个完整的实体而不是分开看待里面的每一个元素,从而避免了之前可能出现的非法参数数目的争议情况发生。 另外值得注意的一点是在创建对象实例的过程中也有可能遭遇同样的困扰——即指定初始化所需的那些额外信息(也就是所谓的“带参构造器”)。此时同样需遵循相同的准则来进行相应的设置工作以防止意外状况的发生[^4]^。 最后提醒一点关于访问权限控制方面的考量因素也是不可忽略的部分之一;即使语法层面看起来一切正常但如果涉及到私有级别的组件则仍有必要借助特定手段绕过常规限制才能顺利完成任务[^5]^. ### 结论 综上所述,通过对引起`java.lang.IllegalArgumentException:wrongnumberofarguments`这一常见运行期错误背后逻辑关系深入剖析之后我们可以得出结论说只要严格按照既定规则办事就能很好地规避掉这类麻烦事啦!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值