Package com.anthavio.httl.util

Source Code of com.anthavio.httl.util.JsonInputGenerator

package com.anthavio.httl.util;

import java.io.IOException;
import java.io.Reader;
import java.nio.charset.Charset;
import java.text.ParseException;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.Map;

import javax.tools.DiagnosticCollector;
import javax.tools.JavaCompiler;
import javax.tools.JavaCompiler.CompilationTask;
import javax.tools.JavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;

import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.databind.ObjectMapper;

/**
*
* @author martin.vanek
*
*/
public class JsonInputGenerator extends JavaCodeGenerator {

  public JsonInputGenerator() {

  }

  public void compile(String className, String javaCode) throws IOException {
    String fileName;
    int dotIdx = className.lastIndexOf('.');
    if (dotIdx != -1) {
      fileName = className.substring(dotIdx + 1) + ".java";
    } else {
      fileName = className;
    }
    if (!fileName.endsWith(".java")) {
      fileName += ".java";
    }
    logger.debug("Compiling " + fileName);
    //javax.tool compiler api is cool as hell
    JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
    DiagnosticCollector<JavaFileObject> diagnosticListener = new DiagnosticCollector<JavaFileObject>();
    StandardJavaFileManager fileManager = compiler.getStandardFileManager(diagnosticListener, Locale.getDefault(),
        Charset.forName("utf-8"));
    JavaFileObject java = new StringJavaObject(fileName, javaCode);
    List<JavaFileObject> compilationUnits = Arrays.asList(java);

    //otherwise classes are written to current directory
    String[] options = new String[] { "-d", "target/classes" };
    List<String> compileOptions = Arrays.asList(options);

    CompilationTask task = compiler.getTask(null, fileManager, diagnosticListener, compileOptions, null,
        compilationUnits);
    Boolean result = task.call();
    /*
    List<Diagnostic<? extends JavaFileObject>> diagnostics = diagnosticListener.getDiagnostics();
    for (Diagnostic<? extends JavaFileObject> diagnosticItem : diagnostics) {
      System.out.format("Error in %s", diagnosticItem);
    }
    */
    fileManager.close();

    if (!result) {
      throw new IllegalArgumentException("Compilation failed " + diagnosticListener.getDiagnostics());
    }

  }

  public AstNode parse(String className, Reader reader) throws IOException {
    ObjectMapper mapper = new ObjectMapper();
    JsonFactory factory = mapper.getFactory();
    JsonParser parser = factory.createJsonParser(reader);
    String xName = className + System.currentTimeMillis();
    stack.add(new AstNode(xName, null, false)); //artificial root element - must stay on the top of the Stack
    doField(className, parser);
    if (!xName.equals(stack.peek().getName())) {
      throw new IllegalStateException("Artificial element " + xName + " not found on the top of the stack");
    }
    AstNode rootEntry = stack.pop().getElements().get(0);
    if (!rootEntry.getName().equals(className)) {
      throw new IllegalStateException("Root element " + className + " does not match with " + rootEntry.getName());
    }
    return rootEntry;
  }

  private void doField(String name, JsonParser parser) throws IOException {
    logger.debug("Field begin " + name);
    JsonToken token = parser.nextToken();
    if (token == JsonToken.START_OBJECT) {
      doObject(name, parser);
    } else if (token == JsonToken.START_ARRAY) {
      doArray(name, parser);
    } else { //must be value then
      Class<?> type = doValue(parser);
      stack.peek().addField(name, type);
    }
    logger.debug("Field ended " + name);
  }

  private AstNode doObject(String name, JsonParser parser) throws IOException {
    logger.debug("Object begin " + name);
    AstNode object = AstNode.object(name);
    stack.push(object);
    while (parser.nextToken() != JsonToken.END_OBJECT) {
      JsonToken token = parser.getCurrentToken();
      if (token == JsonToken.FIELD_NAME) {
        String fieldName = parser.getCurrentName();
        doField(fieldName, parser);
      } else {
        throw new IllegalArgumentException("Unexpected token " + token);
      }
    }
    if (stack.pop() != object) {
      throw new IllegalStateException("Stack corrupted for " + object);
    }
    //System.out.println(object.getName() + " " + object.getTypeName());
    object = declare(object);

    stack.peek().addField(object); //add to parent
    logger.debug("Object ended " + name + " " + object);
    return object;
  }

  private AstNode declare(AstNode object) {
    logger.debug("declare " + object);
    List<AstNode> objects;
    if (doGlobalTypes) {
      objects = globals;
    } else { //!doGlobalTypes
      AstNode parent = stack.peek();
      int s = stack.size();
      while (parent.isArray()) {
        parent = stack.get(--s); //cannot declare in array
      }
      objects = parent.locals;
    }

    //if we already have object with same set of fields - use it instead of creating new
    for (AstNode existing : objects) {
      //System.out.println(object + " vs " + existing);
      if (existing.equalsFields(object)) {
        //System.out.println("existing " + object);
        return existing;
      }
    }

    //object with same set of fields not found - create new
    String typeName = buildClassName(object.getName());
    //check for name collision
    for (AstNode existing : objects) {
      if (existing.getName().equals(typeName)) {
        typeName = stack.peek().getName() + typeName; //use enclosing object name as prefix
      }
    }
    object.setTypeName(typeName);
    objects.add(object);

    return object;
  }

  private AstNode doArray(String name, JsonParser parser) throws IOException {
    logger.debug("Array begin " + name);
    AstNode array = AstNode.array(name);
    stack.push(array);
    int counter = 0;
    AstNode first = null;
    while (parser.nextToken() != JsonToken.END_ARRAY) {
      ++counter;
      JsonToken token = parser.getCurrentToken();
      //We don't know type name for array element - create artificial
      //String eName = array.getName();
      AstNode element;
      if (token == JsonToken.START_OBJECT) {
        element = doObject(name, parser);
      } else if (token == JsonToken.START_ARRAY) {
        element = doArray(name, parser);
      } else { //must be value then
        Class<?> type = doValue(parser);
        if (type == Void.class) {
          continue; //skip JSON null elements
        }
        element = array.addField(name, type);
      }

      if (first == null) {
        first = element;
        //System.out.println("array will be " + element.getTypeName());
        array.setTypeName(element.getTypeName());
      } else if (!first.equalsFields(element)) {
        if (first.isSimpleType() && element.isSimpleType()) {
          //if heterogenity is for example Integer vs String, we can still use to String...
          logger.debug("Heterogenous simple type array " + name + " of " + first.getTypeName() + " vs "
              + element.getTypeName());
          array.setTypeName(String.class);
        } else {
          if ((first.isSimpleType() && !element.isSimpleType()) || (!first.isSimpleType() && element.isSimpleType())) {
            throw new IllegalStateException("Mixing simple and complex types in array is not allowed: "
                + first.getTypeName() + " vs " + element.getTypeName());
          }
          logger.warn("Heterogenous complex type array " + name + " of " + first.getTypeName() + " vs "
              + element.getTypeName());
          first.setTypeName(first.getTypeName() + "1");//distinguish class names
          element.setTypeName(element.getTypeName() + counter);
          array.setTypeName(Map.class); //Jackson can parse anything into Map
        }
      }
    }

    if (stack.pop() != array) {
      throw new IllegalStateException("Stack corrupted for " + array);
    }
    stack.peek().addField(array); //add this array into parent object
    logger.debug("Array ended " + name + " " + array);
    return array;
  }

  /**
   * XXX maybe provide some value parser / type resolver for pluggable types instead of this hardcoded stuff
   */
  private Class<?> doValue(JsonParser parser) throws IOException {
    Class<?> type;
    JsonToken token = parser.getCurrentToken();
    String value = parser.getValueAsString();
    switch (token) {
    case VALUE_STRING:
      type = String.class;
      break;
    case VALUE_NUMBER_INT:
      type = Integer.class;
      break;
    case VALUE_NUMBER_FLOAT:
      type = Float.class;
      break;
    case VALUE_TRUE:
      type = Boolean.class;
      break;
    case VALUE_FALSE:
      type = Boolean.class;
      break;
    case VALUE_NULL:
      type = Void.class;
      break;
    default:
      throw new IllegalArgumentException("Unexpected token " + token);
    }
    if (type == String.class && dateFormat != null) {
      try {
        dateFormat.parse(value);
        type = Date.class;
      } catch (ParseException px) {
        //not a date, keep it string
      }
    }
    logger.debug("Value " + value + " of " + type);
    return type;
  }

}
/*
  public static class XmlInputGenerator extends JavaCodeGenerator {
   
    @Override
    public AstNode parse(String className, Reader reader) throws IOException {
      XMLInputFactory factory = XMLInputFactory.newFactory();
      XMLEventReader xmlReader = factory.createXMLEventReader(reader);
      String xName = className + System.currentTimeMillis();
      stack.add(new AstNode(xName, null, false)); //artificial root element - must stay on the top of the Stack
      doField(className, xmlReader);
      if (!xName.equals(stack.peek().getName())) {
        throw new IllegalStateException("Artificial element " + xName + " not found on the top of the stack");
      }
      AstNode rootEntry = stack.pop().getElements().get(0);
      if (!rootEntry.getName().equals(className)) {
        throw new IllegalStateException("Root element " + className + " does not match with " + rootEntry.getName());
      }
      return rootEntry;
    }

    private void doField(String name, XMLEventReader xmlReader) throws IOException {
      logger.debug("Field begin " + name);
      XMLEvent token = xmlReader.nextEvent();
      if (token.getEventType() == XMLEvent.START_ELEMENT) {
        doObject(name, xmlReader);
      } else if (token == JsonToken.START_ARRAY) {
        doArray(name, xmlReader);
      } else { //must be value then
        Class<?> type = doValue(xmlReader);
        stack.peek().addField(name, type);
      }
      logger.debug("Field ended " + name);
    }

    private Class<?> doValue(XMLEventReader xmlReader) throws IOException {
      Class<?> type;
      XMLEvent token = xmlReader.peek();
      String value = xmlReader.getElementText();
      switch (token) {
      case VALUE_STRING:
        type = String.class;
        break;
      case VALUE_NUMBER_INT:
        type = Integer.class;
        break;
      case VALUE_NUMBER_FLOAT:
        type = Float.class;
        break;
      case VALUE_TRUE:
        type = Boolean.class;
        break;
      case VALUE_FALSE:
        type = Boolean.class;
        break;
      case VALUE_NULL:
        type = Void.class;
        break;
      default:
        throw new IllegalArgumentException("Unexpected token " + token);
      }
      if (type == String.class && dateFormat != null) {
        try {
          dateFormat.parse(value);
          type = Date.class;
        } catch (ParseException px) {
          //not a date, keep it string
        }
      }
      logger.debug("Value " + value + " of " + type);
      return type;
    }

    private AstNode doObject(String name, XMLEventReader xmlReader) throws IOException {
      logger.debug("Object begin " + name);
      AstNode object = AstNode.object(name);
      stack.push(object);
      while (xmlReader.nextToken() != JsonToken.END_OBJECT) {
        JsonToken token = xmlReader.peek();
        if (token == JsonToken.FIELD_NAME) {
          String fieldName = xmlReader.getCurrentName();
          doField(fieldName, xmlReader);
        } else {
          throw new IllegalArgumentException("Unexpected token " + token);
        }
      }
      if (stack.pop() != object) {
        throw new IllegalStateException("Stack corrupted for " + object);
      }
      //System.out.println(object.getName() + " " + object.getTypeName());
      object = declare(object);

      stack.peek().addField(object); //add to parent
      logger.debug("Object ended " + name + " " + object);
      return object;
    }
  }
*/
 
TOP

Related Classes of com.anthavio.httl.util.JsonInputGenerator

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.