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

org.modelcc.io.java.JavaModelReader Maven / Gradle / Ivy

Go to download

ModelCC is a model-based parser generator (a.k.a. compiler compiler) that decouples language specification from language processing, avoiding some of the problems caused by grammar-driven parser generators. ModelCC receives a conceptual model as input, along with constraints that annotate it. It is then able to create a parser for the desired textual language and the generated parser fully automates the instantiation of the language conceptual model. ModelCC also includes a built-in reference resolution mechanism that results in abstract syntax graphs, rather than mere abstract syntax trees.

The newest version!
/*
 * ModelCC, distributed under ModelCC Shared Software License, www.modelcc.org
 */

package org.modelcc.io.java;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;

import org.modelcc.IModel;
import org.modelcc.Pattern;
import org.modelcc.Priority;
import org.modelcc.io.ModelReader;
import org.modelcc.language.metamodel.MemberCollectionType;
import org.modelcc.language.metamodel.LanguageModel;
import org.modelcc.metamodel.Model;
import org.modelcc.metamodel.ModelElement;

/**
 * Abstract Java model reader. Template algorithm outline:
 * 
 * 
 * createMetadata()
 * 
 * for each Java class:
 *   createClassElement()
 *   preProcessClass()
 *   for each field:
 *     createFieldElement()
 *     processField()
 *   postProcessClass()
 * 
 * createModel()
 * 
* * @author Fernando Berzal ([email protected]) & Luis Quesada ([email protected]) * * @param ModelCC model * @param Class model element * @param Field model element * @param Model reader metadata */ public abstract class JavaModelReader> extends ModelReader { /** * Root class. */ protected Class root; /** * Constructor * @param root the root class */ public JavaModelReader(Class root) { this.root = root; } /** * Read a model from a root java class. * @return the model * @throws Exception */ @Override public final M read() throws Exception { clearMessages(); if (!IModel.class.isAssignableFrom(root)) throw new ClassDoesNotExtendIModelException("Class "+root+" does not extend IModel."); D metadata = createMetadata(); metadata.setRelevantClasses(detectRelevantClasses(root)); readClasses(metadata); return createModel(metadata); } /** * Reads a model from a given class (included for ensuring backwards compatibility) * * @param type the root class of the model * @return the ModelCC language model * @throws Exception */ public static final LanguageModel read (Class type) throws Exception { JavaLanguageReader jmr = new JavaLanguageReader(type); return jmr.read(); } /** * Create specific instance of JavaModelReaderMetadata * @return Reader metadata */ public abstract D createMetadata (); /** * Create ModelCC model from JavaModelReader metadata * @param metadata Metadata obtained through reflection * @return The resulting ModelCC model * @throws Exception */ public abstract M createModel (D metadata) throws Exception; protected abstract void preProcessClass (Class type, D metadata, C element) throws Exception; protected abstract void postProcessClass (Class type, D metadata, C element) throws Exception; /** * Create ModelCC class model from Java metadata */ protected abstract C createClassElement (Class type); /** * Create ModelCC field model from Java metadata */ protected abstract F createFieldElement (Field field, Class type, D metadata); /** * Field processing */ protected abstract void processField (C element, F field); /** * Reads all the classes information * @param metadata reader metadata * @throws Exception */ private void readClasses(D metadata) throws Exception { C el; for (Class c: metadata.getRelevantClasses()) { el = readClass(c,metadata); metadata.getJavaElements().add(el); } for (Class cact: metadata.getRelevantClasses()) { if (!cact.isPrimitive()) { Class sclass = cact.getSuperclass(); if (IModel.class.isAssignableFrom(sclass)) { metadata.addJavaSubclass(metadata.getClassElement(sclass), metadata.getClassElement(cact)); } } } } /** * Read class information * @param type the element class * @param metadata reader metadata * @throws Excception */ private C readClass(Class type, D metadata) throws Exception { C element = createClassElement(type); preProcessClass(type, metadata, (C) element); // Field members Field[] fields = type.getDeclaredFields(); for (Field field: fields) { F c = createFieldElement(field,type,metadata); if (c != null) { if (!Modifier.isStatic(field.getModifiers())) { element.addMember(c); processField((C)element, c); } } } postProcessClass(type, metadata,(C) element); metadata.setClassElement(type,element); return element; } /** * Detects all the relevant classes from a root one * @param root the root class * @return the set of relevant classes * @throws ClassNotFoundException */ private Set detectRelevantClasses(Class root) throws ClassNotFoundException { LinkedList q = new LinkedList(); Set done = new HashSet(); Class currentClass; // Hack to avoid processing String and Object classes, which makes no sense. done.add(String.class); done.add(Object.class); if (!root.getName().contains("$")) q.addLast(root); while (!q.isEmpty()) { currentClass = q.removeLast(); done.add(currentClass); // Add precedences if (currentClass.isAnnotationPresent(Priority.class)) { Priority an = (Priority) currentClass.getAnnotation(Priority.class); for (int j=0; j subclasses = Reflection.findSubclasses(currentClass); for (Class add: subclasses) { addClass(add, q, done); } } // Add superclass if (!currentClass.isPrimitive()) { addClass( currentClass.getSuperclass(), q, done); } } // Revert hack for avoiding the processing of String and Object classes done.remove(Object.class); done.remove(String.class); return done; } private void addField (Class currentClass, Field field, LinkedList q, Set done) throws ClassNotFoundException { MemberCollectionType collection = null; boolean avoid = false; if (List.class.isAssignableFrom(field.getType())) { if (ArrayList.class.equals(field.getType()) || (List.class.equals(field.getType()))) collection = MemberCollectionType.LIST; else log(Level.SEVERE, "In field \"{0}\" of class \"{1}\": The class of a composite list may only be List or ArrayList.", new Object[]{field.getName(), currentClass.getCanonicalName()}); } else if (Set.class.isAssignableFrom(field.getType())) { if (HashSet.class.equals(field.getType()) || (Set.class.equals(field.getType()))) collection = MemberCollectionType.SET; else log(Level.SEVERE, "In field \"{0}\" of class \"{1}\": The class of a composite set may only be Set or HashSet.", new Object[]{field.getName(), currentClass.getCanonicalName()}); } else if (Map.class.isAssignableFrom(field.getType())) { avoid = true; } else if (field.getType().isArray()) { collection = MemberCollectionType.ARRAY; } if (!avoid) { Class add = Reflection.getType(collection,field); if (add != null) { if (IModel.class.isAssignableFrom(currentClass)) addClass(add, q, done); } } } /** * Adds a class to a queue if it hasn't been added before * @param add the class to add * @param q the queue * @param done the already added classes * @return true if it has been added now, false if it was added before * @throws ClassNotFoundException */ private boolean addClass(Class add,LinkedList q,Set done) throws ClassNotFoundException { if (!done.contains(add) && !q.contains(add) && IModel.class.isAssignableFrom(add) && !add.getName().contains("$")) { q.addLast(add); return true; } return false; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy