All Downloads are FREE. Search and download functionalities are using the official Maven repository.

juzu.impl.common.MethodHandle Maven / Gradle / Ivy

There is a newer version: 1.2.0
Show newest version
/*
 * Copyright 2013 eXo Platform SAS
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package juzu.impl.common;

import java.lang.reflect.GenericArrayType;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;

/**
 * Uniquely identifies a method.
 *
 * @author Julien Viet
 */
public final class MethodHandle implements Iterable {

  public static MethodHandle parse(String s) throws NullPointerException, IllegalArgumentException {
    int method = s.indexOf('#');
    if (method == -1) {
      throw new IllegalArgumentException("Invalid method handle " + s);
    }
    int leftParenthesis = s.indexOf('(', method + 1);
    if (leftParenthesis == -1 || leftParenthesis > s.length() - 2) {
      throw new IllegalArgumentException("Invalid method handle " + s);
    }
    if (s.charAt(s.length() - 1) != ')') {
      throw new IllegalArgumentException("Invalid method handle " + s);
    }

    //
    String type = s.substring(0, method);
    String name = s.substring(method + 1, leftParenthesis);

    //
    if (s.length() - leftParenthesis == 2) {
      return new MethodHandle(type, name);
    } else {
      String[] list = EMPTY_STRINGS;
      for (String parameter : Spliterator.split(s, leftParenthesis + 1, s.length() - 1, ',', new ArrayList())) {
        if (parameter.length() == 0) {
          throw new IllegalArgumentException();
        }
        list = Tools.appendTo(list, parameter);
      }
      return new MethodHandle(type, name, list);
    }
  }

  /** . */
  private static final String[] EMPTY_STRINGS = new String[0];

  /** . */
  private final String type;

  /** . */
  private final String name;

  /** . */
  private final String[] parameters;

  /** . */
  private String toString;

  public MethodHandle(Method method) throws NullPointerException {
    if (method == null) {
      throw new NullPointerException("No null method accepted");
    }

    Type[] parameterTypes = method.getGenericParameterTypes();
    String[] parameters = new String[parameterTypes.length];
    StringBuilder sb = new StringBuilder();
    for (int i = 0;i < parameters.length;i++) {
      format(parameterTypes[i], sb);
      parameters[i] = sb.toString();
      sb.setLength(0);
    }

    //
    this.type = method.getDeclaringClass().getName();
    this.name = method.getName();
    this.parameters = parameters.clone();
    this.toString = null;
  }

  private void format(Type type, StringBuilder sb) {
    if (type instanceof Class) {
      Class classType = (Class)type;
      if (classType.isArray()) {
        format(classType.getComponentType(), sb);
        sb.append("[]");
      } else {
        sb.append(classType.getName());
      }
    } else if (type instanceof ParameterizedType) {
      ParameterizedType parameterizedType = (ParameterizedType)type;
      format(parameterizedType.getRawType(), sb);
      sb.append('<');
      Type[] typeArguments = parameterizedType.getActualTypeArguments();
      for (int i = 0;i < typeArguments.length;i++) {
        if (i > 0) {
          sb.append(',');
        }
        format(typeArguments[i], sb);
      }
      sb.append('>');
    } else if (type instanceof GenericArrayType) {
      GenericArrayType arrayType = (GenericArrayType)type;
      format(arrayType.getGenericComponentType(), sb);
      sb.append("[]");
    } else {
      throw new UnsupportedOperationException("todo " + type);
    }
  }

  public MethodHandle(String type, String name) {
    this.type = type;
    this.name = name;
    this.parameters = EMPTY_STRINGS;
  }

  public MethodHandle(String type, String name, String... parameters) {
    this.type = type;
    this.name = name;
    this.parameters = parameters.length == 0 ? parameters : parameters.clone();
  }

  public String getType() {
    return type;
  }

  public String getName() {
    return name;
  }

  public int getParameterSize() {
    return parameters.length;
  }

  public String getParameterAt(int index) throws IndexOutOfBoundsException {
    if (index < 0 || index > parameters.length) {
      throw new IndexOutOfBoundsException("Bad index " + index);
    }
    return parameters[index];
  }

  public Iterator iterator() {
    return Tools.iterator(parameters);
  }

  @Override
  public int hashCode() {
    return type.hashCode() ^ name.hashCode() ^ Arrays.hashCode(parameters);
  }

  @Override
  public boolean equals(Object obj) {
    if (obj == this) {
      return true;
    }
    if (obj instanceof MethodHandle) {
      MethodHandle that = (MethodHandle)obj;
      return type.equals(that.type) && name.equals(that.name) && Arrays.equals(parameters, that.parameters);
    }
    return false;
  }

  @Override
  public String toString() {
    if (toString == null) {
      toString = Tools.join(new StringBuilder().append(type).append('#').append(name).append('('), ',', parameters).append(')').toString();
    }
    return toString;
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy