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

com.jaxio.celerio.model.support.jpa.JpaAttribute Maven / Gradle / Ivy

There is a newer version: 4.0.23
Show newest version
/*
 * Copyright 2015 JAXIO http://www.jaxio.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 com.jaxio.celerio.model.support.jpa;

import com.jaxio.celerio.configuration.MetaAttribute;
import com.jaxio.celerio.configuration.SequencePattern;
import com.jaxio.celerio.configuration.entity.EnumConfig;
import com.jaxio.celerio.configuration.entity.GeneratedValue;
import com.jaxio.celerio.configuration.entity.GenericGenerator;
import com.jaxio.celerio.model.Attribute;
import com.jaxio.celerio.spi.support.AbstractAttributeSpi;
import com.jaxio.celerio.util.AnnotationBuilder;
import com.jaxio.celerio.util.AttributeBuilder;
import org.springframework.util.Assert;

import java.util.Iterator;
import java.util.List;

import static java.lang.Boolean.FALSE;
import static java.lang.Boolean.TRUE;
import static org.apache.commons.lang.StringUtils.isBlank;

public class JpaAttribute extends AbstractAttributeSpi {

    public JpaAttribute(Attribute attribute) {
        init(attribute);
    }

    @Override
    public String velocityVar() {
        return "jpa--NOT-YET-USED"; // TODO: use it
    }

    @Override
    public Object getTarget() {
        return this;
    }

    public List getAnnotations() {
        AnnotationBuilder ab = new AnnotationBuilder();
        ab.add(
                getTransientAnnotation(), //
                getIdAnnotation(), //
                getLobAnnotation(), //
                getEnumAnnotation(), //
                getBasicAnnotation(), //
                getColumnAnnotation(), //
                getVersionAnnotation(), //
                getTemporalAnnotation(), //
                getHibernateTypeAnnotation(), //
                getGeneratedValueAnnotation(), //
                getSequenceGeneratorAnnotation(), //
                getGenericGeneratorAnnotation());
        return ab.getAnnotations();
    }

    public String getTransientAnnotation() {
        if (attribute.getColumnConfig() == null //
                || attribute.getColumnConfig().getAsTransient() == null //
                || attribute.getColumnConfig().getAsTransient() == FALSE) {
            return null;
        }
        addImport("javax.persistence.Transient");
        return "@Transient";
    }

    public String getIdAnnotation() {
        if (attribute.isSimplePk()) {
            addImport("javax.persistence.Id");
            return "@Id";
        } else {
            return null;
        }
    }

    public String getHibernateTypeAnnotation() {
        if (attribute.getColumnConfig() == null) {
            return null;
        }
        if (attribute.getColumnConfig().getTypeConverter() != null) {
            StringBuffer annotation = new StringBuffer("");
            addImport("org.hibernate.annotations.Type");
            annotation.append("@Type(type = \"").append(attribute.getColumnConfig().getTypeConverter()).append("\")");
            return annotation.toString();
        } else if (attribute.getColumnConfig().hasEnum() && attribute.getColumnConfig().getEnumConfig().isCustomType()) {
            StringBuffer annotation = new StringBuffer("");

            EnumConfig enumConfig = attribute.getColumnConfig().getEnumConfig();

            addImport("org.hibernate.annotations.Type");
            addImport("org.hibernate.annotations.Parameter");

            if (enumConfig.hasUserType()) {
                addImport(enumConfig.getUserType());
                annotation.append("@Type(type = " + enumConfig.getUserType() + ", parameters = { @Parameter(name = \"class\", value = \""
                        + attribute.getEntity().getModel().getFullType() + "\"), @Parameter(name = \"attribute\", value = \"" + attribute.getVar() + "\") })");
            } else {
                annotation.append("@Type(type=\"org.jadira.usertype.corejava.PersistentEnum\", parameters={ //\n");
                annotation.append("@Parameter(name=\"enumClass\", value=\"" + attribute.getFullType() + "\"), //\n");
                annotation.append("@Parameter(name=\"valueOfMethod\", value=\"fromValue\"), //\n");
                annotation.append("@Parameter(name=\"identifierMethod\", value=\"getValue\") //\n");
                annotation.append("})");
            }
            return annotation.toString();
/*
        // NOT NEEDED WITH HIBERNATE 5.
        } else if (attribute.getMappedType() == MappedType.M_LOCALDATE) {
            addImport("org.hibernate.annotations.Type");
            String hibernateType = "org.jadira.usertype.dateandtime.joda.PersistentLocalDate";
            if (attribute.getConfig().getCelerio().getConfiguration().hasJodaTime()) {
                hibernateType = attribute.getConfig().getCelerio().getConfiguration().getJodaTime().getLocalDateHibernateType();
            }
            return "@Type(type = \"" + hibernateType + "\")";
        } else if (attribute.getMappedType() == MappedType.M_LOCALDATETIME) {
            addImport("org.hibernate.annotations.Type");
            String hibernateType = "org.jadira.usertype.dateandtime.joda.PersistentLocalDateTime";
            if (attribute.getConfig().getCelerio().getConfiguration().hasJodaTime()) {
                hibernateType = attribute.getConfig().getCelerio().getConfiguration().getJodaTime().getLocalDateTimeHibernateType();
            }
            return "@Type(type = \"" + hibernateType + "\")";
*/
        } else {
            return null;
        }
    }

    public String getBasicAnnotation() {
        if (attribute.isInPk()) {
            return null;
        }

        AttributeBuilder builder = new AttributeBuilder(getBasicFetch());
        if (builder.isEmpty()) {
            return null;
        }

        // we set it only if LAZY is active and if different from default
        builder.add(getBasicOptional());
        if (builder.isEmpty()) {
            return null;
        }
        addImport("javax.persistence.Basic");
        return "@Basic(" + builder.getAttributes() + ")";
    }

    public String getEnumAnnotation() {
        if (!attribute.isEnum()) {
            return null;
        }
        if (attribute.getColumnConfig().getEnumConfig().isCustomType()) {
            return null;
        }
        addImport("javax.persistence.Enumerated");
        if (attribute.getColumnConfig().getEnumConfig().isString()) {
            addImport("static javax.persistence.EnumType.STRING");
            return "@Enumerated(STRING)";
        } else {
            addImport("static javax.persistence.EnumType.ORDINAL");
            return "@Enumerated(ORDINAL)";
        }
    }

    private String getBasicOptional() {
        if (attribute.isNullable()) {
            return null;
        }
        return "optional = false";
    }

    private String getBasicFetch() {
        if (!attribute.isLazyLoaded()) {
            return null;
        }
        addImport("static javax.persistence.FetchType.LAZY");
        return "fetch = LAZY";
    }

    public String getLobAnnotation() {
        if (!attribute.isLob()) {
            return null;
        }
        addImport("javax.persistence.Lob");
        return "@Lob";
    }

    public String getTemporalAnnotation() {
        if (attribute.isJavaUtilOnlyDate() /* TODO: handle mapping to Calendar */) {
            addImport("javax.persistence.Temporal");
            addImport("static javax.persistence.TemporalType.DATE");
            return "@Temporal(DATE)";
        }

        if (attribute.isJavaUtilDateAndTime()) {
            addImport("javax.persistence.Temporal");
            addImport("static javax.persistence.TemporalType.TIMESTAMP");
            return "@Temporal(TIMESTAMP)";
        }

        if (attribute.isJavaUtilOnlyTime()) {
            addImport("javax.persistence.Temporal");
            addImport("static javax.persistence.TemporalType.TIME");
            return "@Temporal(TIME)";
        }

        return "";
    }

    public String getColumnAnnotation() {
        AttributeBuilder attributes = getColumnAnnotationAttributes();
        if (attributes.isEmpty()) {
            return "";
        } else {
            addImport("javax.persistence.Column");
            return "@Column(" + attributes.getAttributes() + ")";
        }
    }

    private AttributeBuilder getColumnAnnotationAttributes() {
        return new AttributeBuilder(getTable(), //
                getName(), //
                getNullable(), //
                getUnique(), //
                getLength(), //
                getPrecision(), //
                getScale(), //
                getColumnInsertable(), //
                getColumnUpdatable());
    }

    private String getColumnUpdatable() {
        if (isColumnUpdatable()) {
            return null;
        }
        return "updatable = false";
    }

    private boolean isColumnUpdatable() {
        return attribute.isInPk() || !attribute.isInFk();
    }

    private String getColumnInsertable() {
        return isColumnInsertable() ? null : "insertable = false";
    }

    private boolean isColumnInsertable() {
        return isColumnUpdatable();
    }

    private String getName() {
        return "name = \"" + attribute.getColumnNameEscaped() + "\"";
    }

    private String getTable() {
        if (!attribute.getColumnConfig().getTableName().equalsIgnoreCase(attribute.getEntity().getEntityConfig().getTableName())) {
            String secondaryTableName = attribute.getColumnConfig().getTableNameEscaped();
            return "table = \"" + secondaryTableName + "\"";
        }

        return null;
    }

    private String getNullable() {
        return attribute.isSimplePk() || attribute.isNullable() ? null : "nullable = false";
    }

    private String getUnique() {
        return attribute.isSimplePk() || !attribute.isUnique() ? null : "unique = true";
    }

    private String getLength() {
        if (!attribute.isNumeric() && !attribute.isLob() && attribute.getColumnConfig().getSize() != 255) {
            return "length = " + attribute.getColumnConfig().getSize();
        } else {
            return "";
        }
    }

    private String getPrecision() {
        if (attribute.isNumeric() && attribute.getColumnConfig().getSize() != 0) {
            return "precision = " + attribute.getColumnConfig().getSize() + "";
        } else {
            return "";
        }
    }

    private String getScale() {
        if (attribute.isNumeric() && attribute.getColumnConfig().getDecimalDigits() != 0) {
            return "scale = " + attribute.getColumnConfig().getDecimalDigits() + "";
        } else {
            return "";
        }
    }

    public String getVersionAnnotation() {
        if (!attribute.isVersion()) {
            return "";
        }

        if (attribute.getMappedType().isEligibleForVersion()) {
            addImport("javax.persistence.Version");
            return "@Version";
        } else {
            throw new IllegalStateException("The column " + attribute.getFullColumnName() + " type cannot be used with @Version");
        }
    }

    private String getGenericGeneratorStrategy() {
        if (attribute.isSimplePk() && attribute.isString()) {
            if (attribute.getColumnConfig().getSize() == 32) {
                return "uuid";
            } else if (attribute.getColumnConfig().getSize() == 36) {
                // assuming Hibernate 3.6.9 at least
                // avoid this warning:
                // [jpa2222] - 2012-01-20 16:08:58,432 - - Using org.hibernate.id.UUIDHexGenerator which does not generate IETF RFC 4122 compliant UUID values;
                // consider using org.hibernate.id.UUIDGenerator instead
                return "uuid2";
            } else {
                return "assigned";
            }
        }
        return "";
    }

    private String getGeneratedValueGenerator() {
        return "strategy-" + getGenericGeneratorStrategy();
    }

    //-----------------------------------------
    // @GeneratedValue
    //-----------------------------------------

    public String getGeneratedValueAnnotation() {
        if (useSequenceNameShortcut()) {
            return getGeneratedValueForSequenceNameByConfiguration();
        }

        if (attribute.getColumnConfig().useConfigForIdGenerator()) {
            // TODO: explain why we do not directly check attribute.getColumnConfig().hasGeneratedValue() in the if statement above.
            return getGeneratedValueAnnotationByConfiguration();
        } else if (attribute.getAutoIncrement() == TRUE && !attribute.isSimpleFk()) {
            // the jdbc driver supports IS_AUTOINCREMENT metadata, great!
            // if it is an fk, we do not want @GeneratedValue because we use instead @MapsId on the association...
            addImport("javax.persistence.GeneratedValue");
            return "@GeneratedValue";
        } else if (attribute.getAutoIncrement() == FALSE && /* 32 length string are special for us */!attribute.isString()) {
            // the jdbc driver supports IS_AUTOINCREMENT metadata, great!
            return "";
        } else {
            // the jdbc driver does not support IS_AUTOINCREMENT
            // fall back to convention
            return getGeneratedValueAnnotationByConvention();
        }
    }

    private String getGeneratedValueForSequenceNameByConfiguration() {
        addImport("javax.persistence.GeneratedValue");
        addImport("static javax.persistence.GenerationType.SEQUENCE");
        return "@GeneratedValue(strategy = SEQUENCE, " //
                + "generator = \"" + attribute.getEntity().getEntityConfig().getSequenceName() + "\")";
    }

    private String getGeneratedValueAnnotationByConfiguration() {
        if (attribute.getColumnConfig().hasGeneratedValue()) {
            GeneratedValue gv = attribute.getColumnConfig().getGeneratedValue();
            addImport("javax.persistence.GeneratedValue");
            if (gv.hasStrategy() && gv.hasGenerator()) {
                addImport("static javax.persistence.GenerationType." + gv.getStrategy());
                return "@GeneratedValue(strategy = " + gv.getStrategy() + ", generator = \"" + gv.getGenerator() + "\")";
            } else if (gv.hasStrategy()) {
                addImport("static javax.persistence.GenerationType." + gv.getStrategy());
                return "@GeneratedValue(strategy = " + gv.getStrategy() + ")";
            } else {
                return "@GeneratedValue(generator = \"" + gv.getGenerator() + "\")";
            }
        } else {
            return "";
        }
    }

    private String getGeneratedValueAnnotationByConvention() {
        if (hasIdGeneratorByConvention()) {
            String strategy = getGenericGeneratorStrategy();
            addImport("javax.persistence.GeneratedValue");
            if (isBlank(strategy)) {
                return "@GeneratedValue";
            } else {
                return "@GeneratedValue(generator = \"" + getGeneratedValueGenerator() + "\")";
            }
        } else {
            return "";
        }
    }

    public boolean isManuallyAssigned() {
        Assert.isTrue(attribute.isSimplePk(), "isManuallyAssigned can only be requested on simple primary keys");
        return isColumnInsertable() && !uglyHackHasGeneratedValueAnno();
    }

    /**
     * The negation of is isManuallyAssigned().
     */
    public boolean isAutomaticallyAssigned() {
        return !isManuallyAssigned();
    }

    /**
     * mirror the getGeneratedValueAnnotation logic and return true if
     * a GeneratedValue annotation applies.
     * TODO: code review.
     */
    private boolean uglyHackHasGeneratedValueAnno() {
        if (useSequenceNameShortcut()) {
            return true;
        }

        if (attribute.getColumnConfig().useConfigForIdGenerator()) {
            return attribute.getColumnConfig().hasGeneratedValue();
        } else if (attribute.getAutoIncrement() == TRUE) {
            return true;
        } else if (attribute.getAutoIncrement() == FALSE && /* 32 length string are special for us */!attribute.isString()) {
            // the jdbc driver supports IS_AUTOINCREMENT metadata, great!
            return false;
        } else {
            // the jdbc driver does not support IS_AUTOINCREMENT
            // fall back to convention
            return hasIdGeneratorByConvention();
        }
    }


    //-----------------------------------------
    // @SequenceGenerator
    //-----------------------------------------

    public String getSequenceGeneratorAnnotation() {
        if (useSequenceNameShortcut()) {
            return getSequenceGeneratorAnnotationByConfiguration();
        }
        return "";
    }

    private boolean useSequenceNameShortcut() {
        return attribute.isSimplePk()  //
                && attribute.getEntity().isRoot() //
                && attribute.isNumeric() //
                && !attribute.getColumnConfig().useConfigForIdGenerator() //
                && attribute.getEntity().getEntityConfig().hasSequenceName()
                && !attribute.isSimpleFk(); // In that case we use @MapsId on one-to-one.
    }

    private String getSequenceGeneratorAnnotationByConfiguration() {
        addImport("javax.persistence.SequenceGenerator");

        // The sequence name is known, we are looking for extra info such as initialValue and allocationSize.
        // It may seems clumsy but our promise is to keep it simple for the user, we do not want to introduce
        // a SequenceGenerator config under columnConfig as it would have no added value compare to working 
        // directly in Java. Here it is a bit transparent and the configuration is rather simple for the user.

        SequencePattern sequencePattern = null;
        List sequences = attribute.getConfig().getCelerio().getConfiguration().getSequences();
        if (sequences != null) {
            for (SequencePattern sequence : sequences) {
                if (sequence.match(attribute.getEntity().getTableName())) {
                    sequencePattern = sequence;
                    break;
                }
            }
        }

        AttributeBuilder ab = new AttributeBuilder();
        // Attention: the sequencePattern does not contain the sequenceName, it contains a pattern...
        ab.addString("name", attribute.getEntity().getEntityConfig().getSequenceName());
        ab.addString("sequenceName", attribute.getEntity().getEntityConfig().getSequenceName());

        if (sequencePattern != null) {
            if (sequencePattern.hasCatalog()) {
                ab.addString("catalog", sequencePattern.getCatalog());
            }

            if (sequencePattern.hasSchema()) {
                ab.addString("schema", sequencePattern.getSchema());
            }

            if (sequencePattern.hasNonDefaultInitialValue()) {
                ab.addInt("initialValue", sequencePattern.getInitialValue());
            }

            if (sequencePattern.hasNonDefaultAllocationSize()) {
                ab.addInt("allocationSize", sequencePattern.getAllocationSize());
            }
        }

        return ab.bindAttributesTo("@SequenceGenerator");
    }

    //-----------------------------------------
    // @GenericGenerator
    //-----------------------------------------


    public String getGenericGeneratorAnnotation() {
        if (useSequenceNameShortcut()) {
            return "";
        } else if (attribute.getColumnConfig().useConfigForIdGenerator()) {
            return getGenericGeneratorAnnotationByConfiguration();
        } else {
            return getGenericGeneratorAnnotationByConvention();
        }
    }

    private String getGenericGeneratorAnnotationByConfiguration() {
        if (attribute.getColumnConfig().hasGenericGenerator()) {
            GenericGenerator gg = attribute.getColumnConfig().getGenericGenerator();
            addImport("org.hibernate.annotations.GenericGenerator");

            AttributeBuilder ggab = new AttributeBuilder();
            ggab.addString("name", gg.getName());
            ggab.addString("strategy", gg.getStrategy());

            if (gg.getParameters().size() > 0) {
                addImport("org.hibernate.annotations.Parameter");

                String[] parameters = new String[gg.getParameters().size()];
                Iterator iter = gg.getParameters().iterator();

                for (int i = 0; i < parameters.length; i++) {
                    MetaAttribute metaAttribute = iter.next();
                    AttributeBuilder pab = new AttributeBuilder();
                    pab.addString("name", metaAttribute.getName());
                    pab.addString("value", metaAttribute.getValue());
                    parameters[i] = pab.bindAttributesTo("@Parameter");
                }
                ggab.add("parameters", parameters);
            }

            return ggab.bindAttributesTo("@GenericGenerator");
        } else {
            return "";
        }
    }

    private String getGenericGeneratorAnnotationByConvention() {
        if (!hasIdGeneratorByConvention()) {
            return null;
        }
        String strategy = getGenericGeneratorStrategy();
        if (isBlank(strategy)) {
            return null;
        }

        addImport("org.hibernate.annotations.GenericGenerator");
        return "@GenericGenerator(name = \"" + getGeneratedValueGenerator() + "\", strategy = \"" + strategy + "\")";
    }

    public boolean hasIdGeneratorByConvention() {
        return attribute.isSimplePk() && !attribute.isDate() && !"assigned".equals(getGenericGeneratorStrategy());
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy