Normal calls depend on the JAR packages of business clients. Generic calls do not depend on second-party packages. A generic call passes the name of the method to be called, the method signature, and parameter values by using GenericService. Generic calls are applicable to specific gateway applications that cannot depend on all the service-specific second-party packages. The hsf-ops service testing also depends on generic calls.

Prerequisites

Use an API to configure an HSF service

You can set generic to true in HSFConsumerBean so that the HSF consumer ignores failures of API loading.

HSFApiConsumerBean hsfApiConsumerBean = new HSFApiConsumerBean();
hsfApiConsumerBean.setInterfaceName("com.alibaba.middleware.hsf.guide.api.service.OrderService");
hsfApiConsumerBean.setVersion("1.0.0");
hsfApiConsumerBean.setGroup("HSF");
// [Specify] generic settings: hsfApiConsumerBean.setGeneric("true");
hsfApiConsumerBean.init(true);

// Use GenericService to obtain the proxy: GenericService genericOrderService = (GenericService) hsfApiConsumerBean.getObject();
// ---------------------- Call -----------------------//
// [Call] Initiate an HSF generic call that returns results of the Map type.
Map orderModelMap = (Map) genericOrderService.$invoke("queryOrder",
                            // The array of input parameter types of the method (xxx.getClass().getName()).
                            new String[] { Long.class.getName() },
                            // Parameters. If a parameter is of the plain old Java object (POJO) type, the parameter must be converted to the Map type.
                            new Object[] { 1L});

The $invoke method that is provided by GenericService contains the name of the actually called method, type of the input parameters, and parameters. This helps the provider find the actual method. Provider-dependent API JAR packages are unavailable. Therefore, an input parameter of the custom data transfer object (DTO) type must be converted to the Map type that can be serialized by the consumer.

Call method and parameter description
  • If a method does not have input parameters, you can pass only the method name. Example: service.$invoke("sayHello", null, null).
  • The generic method type is supported, such as List<String>. Pass only java.util.List that is the value of List.class.getName(). Do not pass java.util.List<String>. Otherwise, the method cannot be found.
  • If the format of a method is uncertain, you can write a unit testing that depends on the second-party package for generic calls. A description format of the Map type for POJO Bean can be generated by using the generalize() method of the com.taobao.hsf.util.PojoUtils utility class that is provided by HSF.
    Map pojoMap = (Map) PojoUtils.generalize(new OrderModel());
  • Demo for passing parameters of the POJO type:
     class User {
        private String name;
        private int age;
        // Use the standard POJO format. The getter and setter methods are omitted here.
       }
    
       // Directly use the Map type to construct a generic parameter of the POJO type: Map param = new HashMap<String, Object>();
       param.put("age", 11);
       param.put("name","Miles");
       // If the input parameter is a child class of the declared parameter type, pass the class field to indicate the actual type of the POJO. The provider must support this type.
       param.put("class", "com.taobao.User");

Use Spring to configure an HSF service

Spring Framework is a component that is widely used in applications. If you do not want to configure HSF services by using an API, you can configure them by using Spring XML. The following XML configuration has the same effect as the preceding API configuration:

<bean id="CallHelloWorld" class="com.taobao.hsf.app.spring.util.HSFSpringConsumerBean">
    <!--[Specify] the operation for service subscription. -->
    <property name="interfaceName" value="com.alibaba.middleware.hsf.guide.api.service.OrderService"/>
    <!--[Specify] the version of the service. -->
    <property name="version" value="1.0.0"/>
    <!--[Specify] the group to which the service belongs. -->
    <property name="group" value="HSF"/>
    <property name="generic" value="true"/>
</bean>

Usage notes

  • By default, the routing rule does not take effect if the consumer does not include the interface class in a generic call.
  • The performance of a generic call is lower than that of a normal call.
  • A service exception is thrown if -Dhsf.generic.throw.exception=true is configured. The default value is false and indicates that the exception is generalized into the Map type.

    If an exception class exists in your on-premises environment but the exception class is not RuntimeException type or its child class, UndeclaredThrowableException is thrown. This is because the exception is not declared in com.taobao.hsf.remoting.service.GenericService. The actual exception can be retrieved through getCause.

    If the exception class does not exist in your on-premises environment, com.taobao.hsf.util.GenericInvocationException is thrown.