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

net.sf.mmm.code.api.modifier.CodeModifiers Maven / Gradle / Ivy

There is a newer version: 1.0.0-beta7
Show newest version
/* Copyright (c) The m-m-m Team, Licensed under the Apache License, Version 2.0
 * http://www.apache.org/licenses/LICENSE-2.0 */
package net.sf.mmm.code.api.modifier;

import java.beans.Visibility;
import java.io.IOException;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;

import net.sf.mmm.code.api.member.CodeMethod;
import net.sf.mmm.util.io.api.IoMode;
import net.sf.mmm.util.io.api.RuntimeIoException;

/**
 * Represents the visibility of a {@link CodeMethod}.
 *
 * @author Joerg Hohwiller (hohwille at users.sourceforge.net)
 * @since 1.0.0
 */
public class CodeModifiers {

  /** The {@link #getModifiers() modifier} {@value}. */
  public static final String KEY_STATIC = "static";

  /** The {@link #getModifiers() modifier} {@value}. */
  public static final String KEY_FINAL = "final";

  /** The {@link #getModifiers() modifier} {@value}. */
  public static final String KEY_ABSTRACT = "abstract";

  /** The {@link #getModifiers() modifier} {@value}. */
  public static final String KEY_VOLATILE = "volatile";

  /** The {@link #getModifiers() modifier} {@value}. */
  public static final String KEY_TRANSIENT = "transient";

  /** The {@link #getModifiers() modifier} {@value}. */
  public static final String KEY_NATIVE = "native";

  /** The {@link #getModifiers() modifier} {@value}. */
  public static final String KEY_SYNCHRONIZED = "synchronized";

  /** The {@link #getModifiers() modifier} {@value}. */
  private static final String KEY_STRICTFP = "strictfp";

  /**
   * The {@link #getModifiers() modifier} {@value}.
   *
   * @see java.lang.reflect.Method#isDefault()
   */
  public static final String KEY_DEFAULT = "default";

  /** {@link CodeModifiers} for {@code public}. */
  public static final CodeModifiers MODIFIERS_PUBLIC = new CodeModifiers(CodeVisibility.PUBLIC);

  /** {@link CodeModifiers} for {@code public abstract}. */
  public static final CodeModifiers MODIFIERS_PUBLIC_ABSTRACT = new CodeModifiers(CodeVisibility.PUBLIC, KEY_ABSTRACT);

  /** {@link CodeModifiers} for {@code public static}. */
  public static final CodeModifiers MODIFIERS_PUBLIC_STATIC = new CodeModifiers(CodeVisibility.PUBLIC, KEY_STATIC);

  /** {@link CodeModifiers} for {@code public static final}. */
  public static final CodeModifiers MODIFIERS_PUBLIC_STATIC_FINAL = new CodeModifiers(CodeVisibility.PUBLIC, KEY_STATIC, KEY_FINAL);

  /** {@link CodeModifiers} for {@code public final}. */
  public static final CodeModifiers MODIFIERS_PUBLIC_FINAL = new CodeModifiers(CodeVisibility.PUBLIC, KEY_FINAL);

  /** {@link CodeModifiers} for {@code private}. */
  public static final CodeModifiers MODIFIERS_PRIVATE = new CodeModifiers(CodeVisibility.PRIVATE);

  /** {@link CodeModifiers} for {@code private abstract}. */
  public static final CodeModifiers MODIFIERS_PRIVATE_ABSTRACT = new CodeModifiers(CodeVisibility.PRIVATE, KEY_ABSTRACT);

  /** {@link CodeModifiers} for {@code private static}. */
  public static final CodeModifiers MODIFIERS_PRIVATE_STATIC = new CodeModifiers(CodeVisibility.PRIVATE, KEY_STATIC);

  /** {@link CodeModifiers} for {@code private static final}. */
  public static final CodeModifiers MODIFIERS_PRIVATE_STATIC_FINAL = new CodeModifiers(CodeVisibility.PRIVATE, KEY_STATIC, KEY_FINAL);

  /** {@link CodeModifiers} for {@code private final}. */
  public static final CodeModifiers MODIFIERS_PRIVATE_FINAL = new CodeModifiers(CodeVisibility.PRIVATE, KEY_FINAL);

  /** {@link CodeModifiers} for {@code protected}. */
  public static final CodeModifiers MODIFIERS_PROTECTED = new CodeModifiers(CodeVisibility.PROTECTED);

  /** {@link CodeModifiers} for {@code protected abstract}. */
  public static final CodeModifiers MODIFIERS_PROTECTED_ABSTRACT = new CodeModifiers(CodeVisibility.PROTECTED, KEY_ABSTRACT);

  /** {@link CodeModifiers} for {@code protected static}. */
  public static final CodeModifiers MODIFIERS_PROTECTED_STATIC = new CodeModifiers(CodeVisibility.PROTECTED, KEY_STATIC);

  /** {@link CodeModifiers} for {@code protected static final}. */
  public static final CodeModifiers MODIFIERS_PROTECTED_STATIC_FINAL = new CodeModifiers(CodeVisibility.PROTECTED, KEY_STATIC, KEY_FINAL);

  /** {@link CodeModifiers} for {@code protected final}. */
  public static final CodeModifiers MODIFIERS_PROTECTED_FINAL = new CodeModifiers(CodeVisibility.PROTECTED, KEY_FINAL);

  /** {@link CodeModifiers} that is empty (no modifiers). */
  public static final CodeModifiers MODIFIERS = new CodeModifiers(CodeVisibility.DEFAULT);

  /** {@link CodeModifiers} for {@code static}. */
  public static final CodeModifiers MODIFIERS_STATIC = new CodeModifiers(CodeVisibility.DEFAULT, KEY_STATIC);

  /** {@link CodeModifiers} for {@code static final}. */
  public static final CodeModifiers MODIFIERS_STATIC_FINAL = new CodeModifiers(CodeVisibility.DEFAULT, KEY_STATIC, KEY_FINAL);

  /** {@link CodeModifiers} for {@code final}. */
  public static final CodeModifiers MODIFIERS_FINAL = new CodeModifiers(CodeVisibility.DEFAULT, KEY_FINAL);

  /** {@link CodeModifiers} for {@code public default}. */
  public static final CodeModifiers MODIFIERS_PUBLIC_DEFAULT = new CodeModifiers(CodeVisibility.PUBLIC, KEY_DEFAULT);

  private final CodeVisibility visibility;

  private final Set modifiers;

  /**
   * The constructor.
   *
   * @param visibility the {@link Visibility}.
   * @param modifiers the additional modifiers.
   */
  public CodeModifiers(CodeVisibility visibility, String... modifiers) {

    this(visibility, Arrays.asList(modifiers));
  }

  /**
   * The constructor.
   *
   * @param visibility the {@link CodeVisibility}.
   * @param modifiers the {@link #getModifiers() modifiers} excluding the {@link CodeVisibility}.
   */
  public CodeModifiers(CodeVisibility visibility, Collection modifiers) {

    super();
    Objects.requireNonNull(visibility, "visibility");
    this.visibility = visibility;
    Set set = new HashSet<>(modifiers);
    for (String modifier : set) {
      verifyModifier(modifier);
    }
    this.modifiers = Collections.unmodifiableSet(set);
  }

  private static void verifyModifier(String modifier) {

    Objects.requireNonNull(modifier, "modifier");
    if (modifier.isEmpty()) {
      throw new IllegalArgumentException(modifier);
    }
    if (CodeVisibility.of(modifier) != null) {
      throw new IllegalArgumentException(modifier);
    }
  }

  /**
   * @return the {@link CodeVisibility}.
   */
  public CodeVisibility getVisibility() {

    return this.visibility;
  }

  /**
   * @return the {@link Set} with all modifiers (not including the {@link #getVisibility() visibility}).
   */
  public Set getModifiers() {

    return this.modifiers;
  }

  /**
   * @param modifier the {@link #getModifiers() modifier} to add.
   * @return this {@link CodeModifiers} if the given {@code modifier} is already {@link #getModifiers() contained} or a
   *         new instance of {@link CodeModifiers} with the given modifier.
   */
  public CodeModifiers addModifier(String modifier) {

    verifyModifier(modifier);
    if (this.modifiers.contains(modifier)) {
      return this;
    }
    Set newModifiers = new HashSet<>(this.modifiers);
    newModifiers.add(modifier);
    return new CodeModifiers(this.visibility, newModifiers);
  }

  /**
   * @param modifier the {@link #getModifiers() modifier} to remove.
   * @return this {@link CodeModifiers} if the given {@code modifier} is not {@link #getModifiers() contained} or a new
   *         instance of {@link CodeModifiers} without the given modifier.
   */
  public CodeModifiers removeModifier(String modifier) {

    verifyModifier(modifier);
    if (!this.modifiers.contains(modifier)) {
      return this;
    }
    Set newModifiers = new HashSet<>(this.modifiers);
    newModifiers.remove(modifier);
    return new CodeModifiers(this.visibility, newModifiers);
  }

  /**
   * @param newVisibility the new {@link #getVisibility() visibility}
   * @return this {@link CodeModifiers} if it already {@link #getVisibility() has} the given {@link CodeVisibility} or a
   *         new instance of {@link CodeModifiers} with the given {@link CodeVisibility}.
   */
  public CodeModifiers changeVisibility(CodeVisibility newVisibility) {

    if (this.visibility.equals(newVisibility)) {
      return this;
    }
    return new CodeModifiers(newVisibility, this.modifiers);
  }

  /**
   * @return {@code true} if {@link #KEY_ABSTRACT abstract}.
   */
  public boolean isAbstract() {

    return this.modifiers.contains(KEY_ABSTRACT);
  }

  /**
   * @return {@code true} if {@link #KEY_STATIC static}.
   */
  public boolean isStatic() {

    return this.modifiers.contains(KEY_STATIC);
  }

  /**
   * @return {@code true} if {@link #KEY_FINAL final}.
   */
  public boolean isFinal() {

    return this.modifiers.contains(KEY_FINAL);
  }

  /**
   * @return {@code true} if {@link #KEY_DEFAULT default} (e.g. for default methods), {@code false} otherwise.
   * @see #isDefaultVisibility()
   */
  public boolean isDefaultModifier() {

    return this.modifiers.contains(KEY_DEFAULT);
  }

  /**
   * @return {@code true} if {@link #getVisibility() visibility} is {@link CodeVisibility#DEFAULT default},
   *         {@code false} otherwise.
   * @see #isDefaultModifier()
   */
  public boolean isDefaultVisibility() {

    return CodeVisibility.DEFAULT.equals(this.visibility);
  }

  /**
   * @return {@code true} if {@link #getVisibility() visibility} is {@link CodeVisibility#PUBLIC public}, {@code false}
   *         otherwise.
   */
  public boolean isPublic() {

    return CodeVisibility.PUBLIC.equals(this.visibility);
  }

  /**
   * @return {@code true} if {@link #getVisibility() visibility} is {@link CodeVisibility#PRIVATE private},
   *         {@code false} otherwise.
   */
  public boolean isPrivate() {

    return CodeVisibility.PRIVATE.equals(this.visibility);
  }

  /**
   * @return {@code true} if {@link #getVisibility() visibility} is {@link CodeVisibility#PROTECTED protected},
   *         {@code false} otherwise.
   */
  public boolean isProtected() {

    return CodeVisibility.PROTECTED.equals(this.visibility);
  }

  @Override
  public int hashCode() {

    return Objects.hashCode(this.modifiers);
  }

  @Override
  public boolean equals(Object obj) {

    if (this == obj) {
      return true;
    }
    if ((obj == null) || (getClass() != obj.getClass())) {
      return false;
    }
    CodeModifiers other = (CodeModifiers) obj;
    if (!Objects.equals(this.modifiers, other.modifiers)) {
      return false;
    }
    return true;
  }

  @Override
  public String toString() {

    StringBuilder buffer = new StringBuilder(32);
    String visibilityString = this.visibility.toString();
    if (!visibilityString.isEmpty()) {
      buffer.append(visibilityString);
      buffer.append(' ');
    }
    formatModifiers(buffer);
    return buffer.toString();
  }

  /**
   * @param buffer the {@link Appendable} where to append the {@link Appendable}.
   */
  public void formatModifiers(Appendable buffer) {

    try {
      if (isDefaultModifier()) {
        appendModifier(buffer, KEY_DEFAULT);
      }
      if (isAbstract()) {
        appendModifier(buffer, KEY_ABSTRACT);
      }
      if (isStatic()) {
        appendModifier(buffer, KEY_STATIC);
      }
      if (isFinal()) {
        appendModifier(buffer, KEY_FINAL);
      }
      for (String modifier : this.modifiers) {
        if (!KEY_DEFAULT.equals(modifier) && !KEY_ABSTRACT.equals(modifier) && !KEY_STATIC.equals(modifier)
            && !KEY_FINAL.equals(modifier)) {
          appendModifier(buffer, modifier);
        }
      }
    } catch (IOException e) {
      throw new RuntimeIoException(e, IoMode.WRITE);
    }
  }

  private static void appendModifier(Appendable buffer, String modifier) throws IOException {

    buffer.append(modifier);
    buffer.append(' ');
  }

  /**
   * @param javaModifiers the Java {@link Modifier} mask.
   * @return the given {@link Modifier} mask as {@link CodeModifiers}.
   */
  public static CodeModifiers of(int javaModifiers) {

    return of(javaModifiers, false);
  }

  /**
   * @param javaModifiers the Java {@link Modifier} mask.
   * @param defaultMethod - {@code true} for {@link java.lang.reflect.Method#isDefault() default method}, {@code false}
   *        otherwise.
   * @return the given {@link Modifier} mask as {@link CodeModifiers}.
   */
  public static CodeModifiers of(int javaModifiers, boolean defaultMethod) {

    List modifiers = new ArrayList<>();
    if (Modifier.isAbstract(javaModifiers)) {
      modifiers.add(KEY_ABSTRACT);
    }
    if (Modifier.isStatic(javaModifiers)) {
      modifiers.add(KEY_STATIC);
    }
    if (Modifier.isFinal(javaModifiers)) {
      modifiers.add(KEY_FINAL);
    }
    if (Modifier.isNative(javaModifiers)) {
      modifiers.add(KEY_NATIVE);
    }
    if (Modifier.isSynchronized(javaModifiers)) {
      modifiers.add(KEY_SYNCHRONIZED);
    }
    if (Modifier.isTransient(javaModifiers)) {
      modifiers.add(KEY_TRANSIENT);
    }
    if (Modifier.isVolatile(javaModifiers)) {
      modifiers.add(KEY_VOLATILE);
    }
    if (Modifier.isStrict(javaModifiers)) {
      modifiers.add(KEY_STRICTFP);
    }
    String[] modifierArray = modifiers.toArray(new String[modifiers.size()]);
    return new CodeModifiers(CodeVisibility.of(javaModifiers), modifierArray);
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy