Package ch.rasc.extclassgenerator

Source Code of ch.rasc.extclassgenerator.ModelGenerator

/**
* Copyright 2013-2014 Ralph Schaer <ralphschaer@gmail.com>
*
* 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 ch.rasc.extclassgenerator;

import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.ref.SoftReference;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.BeanUtils;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.util.Assert;
import org.springframework.util.DigestUtils;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.ReflectionUtils.FieldCallback;
import org.springframework.util.ReflectionUtils.MethodCallback;
import org.springframework.util.StringUtils;

import ch.rasc.extclassgenerator.association.AbstractAssociation;
import ch.rasc.extclassgenerator.validation.AbstractValidation;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.core.JsonGenerationException;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;

/**
* Generator for creating ExtJS and Touch Model objects (JS code) based on a
* provided class or {@link ModelBean}.
*/
public abstract class ModelGenerator {

  public static final Charset UTF8_CHARSET = Charset.forName("UTF-8");

  private static final Map<JsCacheKey, SoftReference<String>> jsCache = new ConcurrentHashMap<JsCacheKey, SoftReference<String>>();

  private static final Map<ModelCacheKey, SoftReference<ModelBean>> modelCache = new ConcurrentHashMap<ModelCacheKey, SoftReference<ModelBean>>();

  /**
   * Instrospects the provided class, creates a model object (JS code) and
   * writes it into the response. Creates compressed JS code. Method ignores
   * any validation annotations.
   *
   * @param request the http servlet request
   * @param response the http servlet response
   * @param clazz class that the generator should introspect
   * @param format specifies which code (ExtJS or Touch) the generator should
   * create.
   * @throws IOException
   *
   * @see #writeModel(HttpServletRequest, HttpServletResponse, Class,
   * OutputFormat, boolean)
   */
  public static void writeModel(HttpServletRequest request,
      HttpServletResponse response, Class<?> clazz, OutputFormat format)
      throws IOException {
    writeModel(request, response, clazz, format, IncludeValidation.NONE,
        false);
  }

  /**
   * Instrospects the provided class, creates a model object (JS code) and
   * writes it into the response. Method ignores any validation annotations.
   *
   * @param request the http servlet request
   * @param response the http servlet response
   * @param clazz class that the generator should introspect
   * @param format specifies which code (ExtJS or Touch) the generator should
   * create
   * @param debug if true the generator creates the output in pretty format,
   * false the output is compressed
   * @throws IOException
   */
  public static void writeModel(HttpServletRequest request,
      HttpServletResponse response, Class<?> clazz, OutputFormat format,
      boolean debug) throws IOException {
    writeModel(request, response, clazz, format, IncludeValidation.NONE,
        debug);
  }

  /**
   * Instrospects the provided class, creates a model object (JS code) and
   * writes it into the response.
   *
   * @param request the http servlet request
   * @param response the http servlet response
   * @param clazz class that the generator should introspect
   * @param format specifies which code (ExtJS or Touch) the generator should
   * create
   * @param includeValidation specifies if any validation configurations
   * should be added to the model code
   * @param debug if true the generator creates the output in pretty format,
   * false the output is compressed
   * @throws IOException
   */
  public static void writeModel(HttpServletRequest request,
      HttpServletResponse response, Class<?> clazz, OutputFormat format,
      IncludeValidation includeValidation, boolean debug)
      throws IOException {
    ModelBean model = createModel(clazz, includeValidation);
    writeModel(request, response, model, format, debug);
  }

  public static void writeModel(HttpServletRequest request,
      HttpServletResponse response, Class<?> clazz,
      OutputConfig outputConfig) throws IOException {
    ModelBean model = createModel(clazz, outputConfig);
    writeModel(request, response, model, outputConfig);
  }

  /**
   * Creates a model object (JS code) based on the provided {@link ModelBean}
   * and writes it into the response. Creates compressed JS code.
   *
   * @param request the http servlet request
   * @param response the http servlet response
   * @param model {@link ModelBean} describing the model to be generated
   * @param format specifies which code (ExtJS or Touch) the generator should
   * create.
   * @throws IOException
   */
  public static void writeModel(HttpServletRequest request,
      HttpServletResponse response, ModelBean model, OutputFormat format)
      throws IOException {
    writeModel(request, response, model, format, false);
  }

  /**
   * Creates a model object (JS code) based on the provided ModelBean and
   * writes it into the response.
   *
   * @param request the http servlet request
   * @param response the http servlet response
   * @param model {@link ModelBean} describing the model to be generated
   * @param format specifies which code (ExtJS or Touch) the generator should
   * create.
   * @param debug if true the generator creates the output in pretty format,
   * false the output is compressed
   * @throws IOException
   */
  public static void writeModel(HttpServletRequest request,
      HttpServletResponse response, ModelBean model, OutputFormat format,
      boolean debug) throws IOException {
    OutputConfig outputConfig = new OutputConfig();
    outputConfig.setDebug(debug);
    outputConfig.setOutputFormat(format);
    writeModel(request, response, model, outputConfig);
  }

  /**
   * Instrospects the provided class and creates a {@link ModelBean} instance.
   * A program could customize this and call
   * {@link #generateJavascript(ModelBean, OutputFormat, boolean)} or
   * {@link #writeModel(HttpServletRequest, HttpServletResponse, ModelBean, OutputFormat)}
   * to create the JS code. Calling this method does not add any validation
   * configuration.
   *
   * @param clazz the model will be created based on this class.
   * @return a instance of {@link ModelBean} that describes the provided class
   * and can be used for Javascript generation.
   */
  public static ModelBean createModel(Class<?> clazz) {
    return createModel(clazz, IncludeValidation.NONE);
  }

  /**
   * Instrospects the provided class and creates a {@link ModelBean} instance.
   * A program could customize this and call
   * {@link #generateJavascript(ModelBean, OutputFormat, boolean)} or
   * {@link #writeModel(HttpServletRequest, HttpServletResponse, ModelBean, OutputFormat)}
   * to create the JS code. Models are being cached. A second call with the
   * same parameters will return the model from the cache.
   *
   * @param clazz the model will be created based on this class.
   * @param includeValidation specifies what validation configuration should
   * be added
   * @return a instance of {@link ModelBean} that describes the provided class
   * and can be used for Javascript generation.
   */
  public static ModelBean createModel(Class<?> clazz,
      IncludeValidation includeValidation) {
    OutputConfig outputConfig = new OutputConfig();
    outputConfig.setIncludeValidation(includeValidation);
    return createModel(clazz, outputConfig);
  }

  /**
   * Instrospects the provided class, creates a model object (JS code) and
   * returns it. This method does not add any validation configuration.
   *
   * @param clazz class that the generator should introspect
   * @param format specifies which code (ExtJS or Touch) the generator should
   * create
   * @param debug if true the generator creates the output in pretty format,
   * false the output is compressed
   * @return the generated model object (JS code)
   */
  public static String generateJavascript(Class<?> clazz,
      OutputFormat format, boolean debug) {
    ModelBean model = createModel(clazz, IncludeValidation.NONE);
    return generateJavascript(model, format, debug);
  }

  public static String generateJavascript(Class<?> clazz,
      OutputConfig outputConfig) {
    ModelBean model = createModel(clazz, outputConfig);
    return generateJavascript(model, outputConfig);
  }

  /**
   * Instrospects the provided class, creates a model object (JS code) and
   * returns it.
   *
   * @param clazz class that the generator should introspect
   * @param format specifies which code (ExtJS or Touch) the generator should
   * create
   * @param includeValidation specifies what validation configuration should
   * be added to the mode code
   * @param debug if true the generator creates the output in pretty format,
   * false the output is compressed
   * @return the generated model object (JS code)
   */
  public static String generateJavascript(Class<?> clazz,
      OutputFormat format, IncludeValidation includeValidation,
      boolean debug) {
    ModelBean model = createModel(clazz, includeValidation);
    return generateJavascript(model, format, debug);
  }

  /**
   * Creates JS code based on the provided {@link ModelBean} in the specified
   * {@link OutputFormat}. Code can be generated in pretty or compressed
   * format. The generated code is cached unless debug is true. A second call
   * to this method with the same model name and format will return the code
   * from the cache.
   *
   * @param model generate code based on this {@link ModelBean}
   * @param format specifies which code (ExtJS or Touch) the generator should
   * create
   * @param debug if true the generator creates the output in pretty format,
   * false the output is compressed
   * @return the generated model object (JS code)
   */
  public static String generateJavascript(ModelBean model,
      OutputFormat format, boolean debug) {
    OutputConfig outputConfig = new OutputConfig();
    outputConfig.setOutputFormat(format);
    outputConfig.setDebug(debug);
    return generateJavascript(model, outputConfig);
  }

  public static void writeModel(HttpServletRequest request,
      HttpServletResponse response, ModelBean model,
      OutputConfig outputConfig) throws IOException {

    byte[] data = generateJavascript(model, outputConfig).getBytes(
        UTF8_CHARSET);
    String ifNoneMatch = request.getHeader("If-None-Match");
    String etag = "\"0" + DigestUtils.md5DigestAsHex(data) + "\"";

    if (etag.equals(ifNoneMatch)) {
      response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
      return;
    }

    response.setContentType("application/javascript");
    response.setCharacterEncoding(UTF8_CHARSET.name());
    response.setContentLength(data.length);

    response.setHeader("ETag", etag);

    @SuppressWarnings("resource")
    ServletOutputStream out = response.getOutputStream();
    out.write(data);
    out.flush();

  }

  public static ModelBean createModel(final Class<?> clazz,
      final OutputConfig outputConfig) {

    Assert.notNull(clazz, "clazz must not be null");
    Assert.notNull(outputConfig.getIncludeValidation(),
        "includeValidation must not be null");

    ModelCacheKey key = new ModelCacheKey(clazz.getName(),
        outputConfig.getIncludeValidation());
    SoftReference<ModelBean> modelReference = modelCache.get(key);
    if (modelReference != null && modelReference.get() != null) {
      return modelReference.get();
    }

    Model modelAnnotation = clazz.getAnnotation(Model.class);

    final ModelBean model = new ModelBean();

    if (modelAnnotation != null
        && StringUtils.hasText(modelAnnotation.value())) {
      model.setName(modelAnnotation.value());
    }
    else {
      model.setName(clazz.getName());
    }

    if (modelAnnotation != null) {
      model.setIdProperty(modelAnnotation.idProperty());
      model.setPaging(modelAnnotation.paging());
      model.setDisablePagingParameters(modelAnnotation
          .disablePagingParameters());

      model.setCreateMethod(trimToNull(modelAnnotation.createMethod()));
      model.setReadMethod(trimToNull(modelAnnotation.readMethod()));
      model.setUpdateMethod(trimToNull(modelAnnotation.updateMethod()));
      model.setDestroyMethod(trimToNull(modelAnnotation.destroyMethod()));
      model.setMessageProperty(trimToNull(modelAnnotation
          .messageProperty()));
      model.setWriter(trimToNull(modelAnnotation.writer()));
      model.setSuccessProperty(trimToNull(modelAnnotation
          .successProperty()));
      model.setTotalProperty(trimToNull(modelAnnotation.totalProperty()));
      model.setRootProperty(trimToNull(modelAnnotation.rootProperty()));
    }

    final Set<String> hasReadMethod = new HashSet<String>();

    BeanInfo bi;
    try {
      bi = Introspector.getBeanInfo(clazz);
    }
    catch (IntrospectionException e) {
      throw new RuntimeException(e);
    }

    for (PropertyDescriptor pd : bi.getPropertyDescriptors()) {
      if (pd.getReadMethod() != null
          && pd.getReadMethod().getAnnotation(JsonIgnore.class) == null) {
        hasReadMethod.add(pd.getName());
      }
    }

    if (clazz.isInterface()) {
      final List<Method> methods = new ArrayList<Method>();

      ReflectionUtils.doWithMethods(clazz, new MethodCallback() {
        @Override
        public void doWith(Method method)
            throws IllegalArgumentException, IllegalAccessException {
          methods.add(method);
        }
      });

      Collections.sort(methods, new Comparator<Method>() {
        @Override
        public int compare(Method o1, Method o2) {
          return o1.getName().compareTo(o2.getName());
        }
      });

      for (Method method : methods) {
        createModelBean(model, method, outputConfig);
      }
    }
    else {

      final Set<String> fields = new HashSet<String>();

      Set<ModelField> modelFieldsOnType = AnnotationUtils
          .getRepeatableAnnotation(clazz, ModelFields.class,
              ModelField.class);
      for (ModelField modelField : modelFieldsOnType) {
        if (StringUtils.hasText(modelField.value())) {
          ModelFieldBean modelFieldBean;

          if (StringUtils.hasText(modelField.customType())) {
            modelFieldBean = new ModelFieldBean(modelField.value(),
                modelField.customType());
          }
          else {
            modelFieldBean = new ModelFieldBean(modelField.value(),
                modelField.type());
          }

          updateModelFieldBean(modelFieldBean, modelField);
          model.addField(modelFieldBean);
        }
      }

      Set<ModelAssociation> modelAssociationsOnType = AnnotationUtils
          .getRepeatableAnnotation(clazz, ModelAssociations.class,
              ModelAssociation.class);
      for (ModelAssociation modelAssociationAnnotation : modelAssociationsOnType) {
        AbstractAssociation modelAssociation = AbstractAssociation
            .createAssociation(modelAssociationAnnotation);
        if (modelAssociation != null) {
          model.addAssociation(modelAssociation);
        }
      }

      Set<ModelValidation> modelValidationsOnType = AnnotationUtils
          .getRepeatableAnnotation(clazz, ModelValidations.class,
              ModelValidation.class);
      for (ModelValidation modelValidationAnnotation : modelValidationsOnType) {
        AbstractValidation modelValidation = AbstractValidation
            .createValidation(
                modelValidationAnnotation.propertyName(),
                modelValidationAnnotation,
                outputConfig.getIncludeValidation());
        if (modelValidation != null) {
          model.addValidation(modelValidation);
        }
      }

      ReflectionUtils.doWithFields(clazz, new FieldCallback() {

        @Override
        public void doWith(Field field)
            throws IllegalArgumentException, IllegalAccessException {
          if (!fields.contains(field.getName())
              && (field.getAnnotation(ModelField.class) != null
                  || field.getAnnotation(ModelAssociation.class) != null || (Modifier
                  .isPublic(field.getModifiers()) || hasReadMethod
                  .contains(field.getName()))
                  && field.getAnnotation(JsonIgnore.class) == null)) {

            // ignore superclass declarations of fields already
            // found in a subclass
            fields.add(field.getName());
            createModelBean(model, field, outputConfig);

          }
        }

      });
    }

    modelCache.put(key, new SoftReference<ModelBean>(model));
    return model;
  }

  private static void createModelBean(ModelBean model,
      AccessibleObject accessibleObject, OutputConfig outputConfig) {
    Class<?> javaType = null;
    String name = null;
    Class<?> declaringClass = null;

    if (accessibleObject instanceof Field) {
      Field field = (Field) accessibleObject;
      javaType = field.getType();
      name = field.getName();
      declaringClass = field.getDeclaringClass();
    }
    else if (accessibleObject instanceof Method) {
      Method method = (Method) accessibleObject;

      javaType = method.getReturnType();
      if (javaType.equals(Void.TYPE)) {
        return;
      }

      if (method.getName().startsWith("get")) {
        name = StringUtils.uncapitalize(method.getName().substring(3));
      }
      else if (method.getName().startsWith("is")) {
        name = StringUtils.uncapitalize(method.getName().substring(2));
      }
      else {
        name = method.getName();
      }

      declaringClass = method.getDeclaringClass();
    }

    ModelType modelType = null;
    for (ModelType mt : ModelType.values()) {
      if (mt.supports(javaType)) {
        modelType = mt;
        break;
      }
    }

    ModelFieldBean modelFieldBean = null;

    ModelField modelFieldAnnotation = accessibleObject
        .getAnnotation(ModelField.class);
    if (modelFieldAnnotation != null) {

      if (StringUtils.hasText(modelFieldAnnotation.value())) {
        name = modelFieldAnnotation.value();
      }

      if (StringUtils.hasText(modelFieldAnnotation.customType())) {
        modelFieldBean = new ModelFieldBean(name,
            modelFieldAnnotation.customType());
      }
      else {
        ModelType type = null;
        if (modelFieldAnnotation.type() != ModelType.AUTO) {
          type = modelFieldAnnotation.type();
        }
        else {
          type = modelType;
        }

        modelFieldBean = new ModelFieldBean(name, type);
      }

      updateModelFieldBean(modelFieldBean, modelFieldAnnotation);

      model.addField(modelFieldBean);
    }
    else {
      if (modelType != null) {
        modelFieldBean = new ModelFieldBean(name, modelType);
        model.addField(modelFieldBean);
      }
    }

    ModelAssociation modelAssociationAnnotation = accessibleObject
        .getAnnotation(ModelAssociation.class);
    if (modelAssociationAnnotation != null) {
      model.addAssociation(AbstractAssociation.createAssociation(
          modelAssociationAnnotation, model, javaType,
          declaringClass, name));
    }

    if (modelFieldBean != null
        && outputConfig.getIncludeValidation() != IncludeValidation.NONE) {

      Set<ModelValidation> modelValidationAnnotations = AnnotationUtils
          .getRepeatableAnnotation(accessibleObject,
              ModelValidations.class, ModelValidation.class);
      if (!modelValidationAnnotations.isEmpty()) {
        for (ModelValidation modelValidationAnnotation : modelValidationAnnotations) {
          AbstractValidation modelValidation = AbstractValidation
              .createValidation(name, modelValidationAnnotation,
                  outputConfig.getIncludeValidation());
          if (modelValidation != null) {
            model.addValidation(modelValidation);
          }
        }
      }
      else {
        Annotation[] fieldAnnotations = accessibleObject
            .getAnnotations();

        for (Annotation fieldAnnotation : fieldAnnotations) {
          AbstractValidation.addValidationToModel(model,
              modelFieldBean, fieldAnnotation,
              outputConfig.getIncludeValidation());
        }

        if (accessibleObject instanceof Field) {
          PropertyDescriptor pd = BeanUtils.getPropertyDescriptor(
              declaringClass, name);
          if (pd != null && pd.getReadMethod() != null) {
            for (Annotation readMethodAnnotation : pd
                .getReadMethod().getAnnotations()) {
              AbstractValidation.addValidationToModel(model,
                  modelFieldBean, readMethodAnnotation,
                  outputConfig.getIncludeValidation());
            }
          }
        }
      }
    }

  }

  private static void updateModelFieldBean(ModelFieldBean modelFieldBean,
      ModelField modelFieldAnnotation) {

    ModelType type = modelFieldBean.getModelType();

    if (StringUtils.hasText(modelFieldAnnotation.dateFormat())
        && type == ModelType.DATE) {
      modelFieldBean.setDateFormat(modelFieldAnnotation.dateFormat());
    }

    String defaultValue = modelFieldAnnotation.defaultValue();
    if (StringUtils.hasText(defaultValue)) {
      if (ModelField.DEFAULTVALUE_UNDEFINED.equals(defaultValue)) {
        modelFieldBean
            .setDefaultValue(ModelField.DEFAULTVALUE_UNDEFINED);
      }
      else {
        if (type == ModelType.BOOLEAN) {
          modelFieldBean.setDefaultValue(Boolean
              .parseBoolean(defaultValue));
        }
        else if (type == ModelType.INTEGER) {
          modelFieldBean.setDefaultValue(Long.valueOf(defaultValue));
        }
        else if (type == ModelType.FLOAT) {
          modelFieldBean
              .setDefaultValue(Double.valueOf(defaultValue));
        }
        else {
          modelFieldBean.setDefaultValue("\"" + defaultValue + "\"");
        }
      }
    }

    if (modelFieldAnnotation.useNull()
        && (type == ModelType.INTEGER || type == ModelType.FLOAT
            || type == ModelType.STRING || type == ModelType.BOOLEAN)) {
      modelFieldBean.setUseNull(true);
    }

    modelFieldBean.setMapping(trimToNull(modelFieldAnnotation.mapping()));

    if (!modelFieldAnnotation.persist()) {
      modelFieldBean.setPersist(modelFieldAnnotation.persist());
    }

    modelFieldBean.setConvert(trimToNull(modelFieldAnnotation.convert()));
  }

  public static String generateJavascript(ModelBean model, OutputConfig config) {

    if (!config.isDebug()) {
      JsCacheKey key = new JsCacheKey(model, config);

      SoftReference<String> jsReference = jsCache.get(key);
      if (jsReference != null && jsReference.get() != null) {
        return jsReference.get();
      }
    }

    ObjectMapper mapper = new ObjectMapper();
    mapper.configure(JsonGenerator.Feature.QUOTE_FIELD_NAMES, false);

    if (!config.isSurroundApiWithQuotes()) {
      if (config.getOutputFormat() == OutputFormat.EXTJS5) {
        mapper.addMixInAnnotations(ProxyObject.class,
            ProxyObjectWithoutApiQuotesExtJs5Mixin.class);
      }
      else {
        mapper.addMixInAnnotations(ProxyObject.class,
            ProxyObjectWithoutApiQuotesMixin.class);
      }
      mapper.addMixInAnnotations(ApiObject.class, ApiObjectMixin.class);
    }
    else {
      if (config.getOutputFormat() != OutputFormat.EXTJS5) {
        mapper.addMixInAnnotations(ProxyObject.class,
            ProxyObjectWithApiQuotesMixin.class);
      }
    }

    Map<String, Object> modelObject = new LinkedHashMap<String, Object>();
    modelObject.put("extend", "Ext.data.Model");

    if (!model.getAssociations().isEmpty()) {
      Set<String> usesClasses = new HashSet<String>();
      for (AbstractAssociation association : model.getAssociations()) {
        usesClasses.add(association.getModel());
      }

      usesClasses.remove(model.getName());

      if (!usesClasses.isEmpty()) {
        modelObject.put("uses", usesClasses);
      }
    }

    Map<String, Object> configObject = new LinkedHashMap<String, Object>();

    if (StringUtils.hasText(model.getIdProperty())
        && !model.getIdProperty().equals("id")) {
      configObject.put("idProperty", model.getIdProperty());
    }

    configObject.put("fields", model.getFields().values());

    if (!model.getAssociations().isEmpty()) {
      configObject.put("associations", model.getAssociations());
    }

    if (!model.getValidations().isEmpty()) {
      configObject.put("validations", model.getValidations());
    }

    ProxyObject proxyObject = new ProxyObject(model, config);
    if (proxyObject.hasMethods()) {
      configObject.put("proxy", proxyObject);
    }

    if (config.getOutputFormat() == OutputFormat.EXTJS4
        || config.getOutputFormat() == OutputFormat.EXTJS5) {
      modelObject.putAll(configObject);
    }
    else {
      modelObject.put("config", configObject);
    }

    StringBuilder sb = new StringBuilder();
    sb.append("Ext.define(\"").append(model.getName()).append("\",");
    if (config.isDebug()) {
      sb.append("\n");
    }

    String configObjectString;
    try {
      if (config.isDebug()) {
        configObjectString = mapper.writerWithDefaultPrettyPrinter()
            .writeValueAsString(modelObject);
      }
      else {
        configObjectString = mapper.writeValueAsString(modelObject);
      }

    }
    catch (JsonGenerationException e) {
      throw new RuntimeException(e);
    }
    catch (JsonMappingException e) {
      throw new RuntimeException(e);
    }
    catch (IOException e) {
      throw new RuntimeException(e);
    }

    sb.append(configObjectString);
    sb.append(");");

    String result = sb.toString();

    if (config.isUseSingleQuotes()) {
      result = result.replace('"', '\'');
    }

    if (!config.isDebug()) {
      jsCache.put(new JsCacheKey(model, config),
          new SoftReference<String>(result));
    }
    return result;
  }

  private static String trimToNull(String str) {
    String trimmedStr = StringUtils.trimWhitespace(str);
    if (StringUtils.hasLength(trimmedStr)) {
      return trimmedStr;
    }
    return null;
  }

  /**
   * Clears the model and Javascript code caches
   */
  public static void clearCaches() {
    modelCache.clear();
    jsCache.clear();
  }

}
TOP

Related Classes of ch.rasc.extclassgenerator.ModelGenerator

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.