Java tutorial
package org.apache.maven.diagrams.connectors.classes.asm_parser; /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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. */ import java.io.IOException; import java.io.InputStream; import java.text.ParseException; import java.util.LinkedList; import java.util.List; import org.apache.maven.diagrams.connectors.classes.ClassDataSource; import org.apache.maven.diagrams.connectors.classes.ClassDataSourceException; import org.apache.maven.diagrams.connectors.classes.model.ClassModel; import org.apache.maven.diagrams.connectors.classes.model.FieldModel; import org.apache.maven.diagrams.connectors.classes.model.MethodModel; import org.apache.maven.diagrams.connectors.classes.model.ModifierModel; import org.objectweb.asm.ClassReader; import org.objectweb.asm.Opcodes; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.FieldNode; import org.objectweb.asm.tree.MethodNode; /** * Implementation ClassDataSource that uses Asm library to parse the files and to find interclass dependencies * * @author <a href="mailto:ptab@newitech.com">Piotr Tabor</a> * @version $Id$ * */ public class AsmClassDataSource implements ClassDataSource { @SuppressWarnings("unchecked") public ClassModel translateToClassModel(Class c) throws ClassDataSourceException { ClassReader classReader; try { classReader = new ClassReader( AsmClassDataSource.class.getResourceAsStream("/" + c.getName().replace(".", "/") + ".class")); } catch (IOException e) { throw new ClassDataSourceException("Cannot instante class reader for:" + c.getName(), e); } ClassNode classNode = new ClassNode(); classReader.accept(classNode, 0); return translateClassNodeToClassModel(classNode); } public ClassModel translateToClassModel(InputStream is) throws ClassDataSourceException { try { ClassReader classReader = new ClassReader(is); ClassNode classNode = new ClassNode(); classReader.accept(classNode, 0); return translateClassNodeToClassModel(classNode); } catch (IOException e) { throw new ClassDataSourceException("Cannot instante class reader for given inputStream.", e); } } public ClassModel translateToClassModel(String className) throws ClassDataSourceException { try { ClassReader classReader = new ClassReader( AsmClassDataSource.class.getResourceAsStream("/" + className.replace(".", "/") + ".class")); ClassNode classNode = new ClassNode(); classReader.accept(classNode, 0); return translateClassNodeToClassModel(classNode); } catch (IOException e) { throw new ClassDataSourceException("Cannot instante class reader for:" + className, e); } } public ClassModel translateToClassModel(ClassLoader classLoader, String className) throws ClassDataSourceException { try { String res = className.replace(".", "/") + ".class"; InputStream is = classLoader.getResourceAsStream(res); if (is == null) throw new ClassDataSourceException("Cannot find resource :" + res); ClassReader classReader = new ClassReader(is); ClassNode classNode = new ClassNode(); classReader.accept(classNode, 0); return translateClassNodeToClassModel(classNode); } catch (IOException e) { throw new ClassDataSourceException("Cannot instante class reader for:" + className, e); } } /* ==================================================================== */ /** * ClassNode is internal (asm's) model. This function translates all available information form the classNode into * classModel. */ private ClassModel translateClassNodeToClassModel(ClassNode classNode) throws ClassDataSourceException { ClassModel classModel = new ClassModel(); classModel.setClassifiedName(classifiedNameToDotName(classNode.name)); if (classNode.superName != null) classModel.setSuperClassName(classifiedNameToDotName(classNode.superName)); else classModel.setSuperClassName(null); classModel.setFields(translateFields(classNode)); classModel.setMethods(translateMethods(classNode)); classModel.setInterfaces(translateInterfaces(classNode)); classModel.setInterface((classNode.access & Opcodes.ACC_INTERFACE) > 0); return classModel; } /** * The method translates informations about interfaces from classNode into list of qualified interface names (dots * as separator) * * * @param classNode - * source asm's classNode * @return list of qualified interface names. */ @SuppressWarnings("unchecked") private List<String> translateInterfaces(ClassNode classNode) { List<String> result = new LinkedList<String>(); for (String _interface : (List<String>) classNode.interfaces) { result.add(classifiedNameToDotName(_interface)); } return result; } /** * The method get's all informations about methods from classNode and builds list of MethodModel objects. * * @param classNode * @return list of MethodModel objects (about all methods in classNode class) * * @throws ClassDataSourceException */ @SuppressWarnings("unchecked") private List<MethodModel> translateMethods(ClassNode classNode) throws ClassDataSourceException { List<MethodModel> result = new LinkedList<MethodModel>(); for (MethodNode method : (List<MethodNode>) classNode.methods) { try { result.add(translateMethodNode(method, simpleClassName(classNode.name))); } catch (ParseException e) { throw new ClassDataSourceException("Cannot translate MethodNode to MethodModel", e); } } return result; } /** * Translates methodNode (asm's) into MethodModel objects. Translates also <init> methods into constructors * (using simpleClassName). * * @param simpleClassName - * not qualified name of class that constains the methodNode method */ private MethodModel translateMethodNode(MethodNode method, String simpleClassName) throws ParseException { MethodModel methodModel = new MethodModel(); methodModel.setName(method.name.equals("<init>") ? simpleClassName : method.name); methodModel.setModifiers(ModifierModel.accessContantsToModifiers(method.access)); DescriptionParser descriptionParser = new DescriptionParser(method.desc); methodModel.setParams(descriptionParser.readParamsList()); methodModel.setType(descriptionParser.readType()); return methodModel; } /** * The method get's all informations about fields from classNode and builds list of FieldModel objects. * * @param classNode * @return list of FieldModel objects (about all fields in classNode class) * * @throws ClassDataSourceException */ @SuppressWarnings("unchecked") private List<FieldModel> translateFields(ClassNode classNode) throws ClassDataSourceException { List<FieldModel> result = new LinkedList<FieldModel>(); for (FieldNode field : (List<FieldNode>) classNode.fields) { try { result.add(translateFieldNode(field)); } catch (ParseException e) { throw new ClassDataSourceException("Cannot translate MethodNode to MethodModel", e); } } return result; } /** * Translates single FieldNode (asm's) into FieldModel * * @param field * @return * @throws ParseException */ private FieldModel translateFieldNode(FieldNode field) throws ParseException { FieldModel fieldModel = new FieldModel(); fieldModel.setName(field.name); fieldModel.setModifiers(ModifierModel.accessContantsToModifiers(field.access)); DescriptionParser descriptionParser = new DescriptionParser(field.desc); fieldModel.setType(descriptionParser.readType()); return fieldModel; } /** * Translates the "/" notation of class name into "." notation. For example java/lang/String is transalted into * java.lang.String * * @param nam * to be translated * @return */ protected String classifiedNameToDotName(String name) { return name.replace('/', '.'); } /** * Translates qualified (by slashes) class name into simpleClassName * * @param name * @return */ protected String simpleClassName(String name) { int last = name.lastIndexOf('/') + 1; return name.substring(last); } }