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

org.eclipse.xtext.xbase.jvmmodel.JvmModelCompleter Maven / Gradle / Ivy

/*******************************************************************************
 * Copyright (c) 2012 itemis AG (http://www.itemis.eu) and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *******************************************************************************/
package org.eclipse.xtext.xbase.jvmmodel;

import static com.google.common.collect.Iterables.*;

import java.lang.annotation.Annotation;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;

import javax.annotation.Generated;

import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.xtext.common.types.JvmAnnotationReference;
import org.eclipse.xtext.common.types.JvmAnnotationType;
import org.eclipse.xtext.common.types.JvmConstructor;
import org.eclipse.xtext.common.types.JvmDeclaredType;
import org.eclipse.xtext.common.types.JvmEnumerationLiteral;
import org.eclipse.xtext.common.types.JvmEnumerationType;
import org.eclipse.xtext.common.types.JvmFormalParameter;
import org.eclipse.xtext.common.types.JvmGenericType;
import org.eclipse.xtext.common.types.JvmIdentifiableElement;
import org.eclipse.xtext.common.types.JvmOperation;
import org.eclipse.xtext.common.types.JvmStringAnnotationValue;
import org.eclipse.xtext.common.types.JvmType;
import org.eclipse.xtext.common.types.JvmTypeReference;
import org.eclipse.xtext.common.types.JvmVisibility;
import org.eclipse.xtext.common.types.TypesFactory;
import org.eclipse.xtext.common.types.util.AnnotationLookup;
import org.eclipse.xtext.common.types.util.TypeReferences;
import org.eclipse.xtext.xbase.compiler.GeneratorConfig;
import org.eclipse.xtext.xbase.compiler.IGeneratorConfigProvider;
import org.eclipse.xtext.xbase.compiler.JvmModelGenerator;

import com.google.common.base.Strings;
import com.google.inject.Inject;

/**
 * Adds expected default values to a created JvmModel.
 * This is not meant to be enhanced in a language specific way, but really just to add things which
 * are implicit in the Java language, such as default constructors or that a class extends java.lang.Object
 * 
 * @author Sven Efftinge - Initial contribution and API
 * 
 * @noextend This class is not intended to be subclassed by clients.
 * @noinstantiate This class is not intended to be instantiated by clients.
 * @noreference This class is not intended to be referenced by clients.
 * 
 * @since 2.7
 */
public class JvmModelCompleter {
	
	protected static final String GENERATED_COMMENT_VAR_SOURCE_FILE = "${sourcefile}";
	
	@Inject 
	private TypeReferences references;
	
	@Inject 
	private TypesFactory typesFactory;
	
	@Inject 
	private JvmTypeExtensions typeExtensions;  
	
	@Inject
	private IJvmModelAssociations associations;
	
	@Inject
	private IJvmModelAssociator associator;

	@Inject
	private JvmAnnotationReferenceBuilder.Factory annotationRefBuilderFactory;
	
	@Inject
	private IGeneratorConfigProvider generatorConfigProvider;
	
	@Inject
	private AnnotationLookup annotationLookup;
	
	/** The generator is used to fill information of the @Generated annotation. */
	@Inject
	private JvmModelGenerator generator;
	
	private DateFormat dateFormat;
	
	public void complete(Iterable elements) {
		for (JvmIdentifiableElement element : elements) {
			complete(element);
		}
	}
	
	public void complete(JvmIdentifiableElement element) {
		if (element instanceof JvmGenericType) {
			completeJvmGenericType((JvmGenericType)element);
		}
		if (element instanceof JvmDeclaredType) {
			JvmDeclaredType declaredType = (JvmDeclaredType) element;
			complete(declaredType.getMembers());
		}
		if(element instanceof JvmConstructor) {
			completeJvmConstructor((JvmConstructor) element);
		}
		if (element instanceof JvmEnumerationType) {
			completeJvmEnumerationType((JvmEnumerationType)element);
		}
		if (element instanceof JvmEnumerationLiteral) {
			completeJvmEnumerationLiteral((JvmEnumerationLiteral)element);
		}
		if (element instanceof JvmAnnotationType) {
			completeJvmAnnotationType((JvmAnnotationType)element);
		}
	}
	
	protected void completeJvmEnumerationType(JvmEnumerationType element) {
		if (element.getSuperTypes().isEmpty()) {
			JvmTypeReference objectType = references.getTypeForName(Enum.class, element,
					references.createTypeRef(element));
			if (objectType != null)
				element.getSuperTypes().add(objectType);
		}
		addAnnotations(element);
		EObject primarySourceElement = associations.getPrimarySourceElement(element);
		JvmOperation values = typesFactory.createJvmOperation();
		values.setVisibility(JvmVisibility.PUBLIC);
		values.setStatic(true);
		values.setSimpleName("values");
		values.setReturnType(references.createArrayType(references.createTypeRef(element)));
		typeExtensions.setSynthetic(values, true);
		if (primarySourceElement != null) {
			associator.associate(primarySourceElement, values);
		}
		element.getMembers().add(values);
		
		JvmOperation valueOf = typesFactory.createJvmOperation();
		valueOf.setVisibility(JvmVisibility.PUBLIC);
		valueOf.setStatic(true);
		valueOf.setSimpleName("valueOf");
		valueOf.setReturnType(references.createTypeRef(element));
		JvmFormalParameter param = typesFactory.createJvmFormalParameter();
		param.setName("name");
		param.setParameterType(references.getTypeForName(String.class, element));
		valueOf.getParameters().add(param);
		typeExtensions.setSynthetic(valueOf, true);
		if (primarySourceElement != null) {
			associator.associate(primarySourceElement, valueOf);
		}
		element.getMembers().add(valueOf);
	}

	protected void completeJvmEnumerationLiteral(JvmEnumerationLiteral element) {
		if (element.getType() == null) {
			element.setType(references.createTypeRef(element.getDeclaringType()));
		}
		element.setStatic(true);
	}

	protected void completeJvmAnnotationType(JvmAnnotationType element) {
		addAnnotations(element);
		if (element.getSuperTypes().isEmpty()) {
			JvmTypeReference objectType = references.getTypeForName(Annotation.class, element);
			if (objectType != null)
				element.getSuperTypes().add(objectType);
		}
	}
	
	public void completeJvmConstructor(JvmConstructor constructor) {
		JvmDeclaredType declaringType = constructor.getDeclaringType();
		if(declaringType != null) {
			String simpleName = declaringType.getSimpleName();
			if(simpleName != null) {
				constructor.setSimpleName(simpleName);
				return;
			}
		}
		constructor.setSimpleName("unset");
	}
	
	protected void completeJvmGenericType(JvmGenericType element) {
		// if no super type add Object
		ensureSuperTypeObject(element);
		addAnnotations(element);
		if (!element.isInterface()) {
			// if no constructors have been added, add a default constructor
			if (isEmpty(element.getDeclaredConstructors())) {
				JvmConstructor constructor = TypesFactory.eINSTANCE.createJvmConstructor();
				constructor.setSimpleName(element.getSimpleName());
				constructor.setVisibility(JvmVisibility.PUBLIC);
				typeExtensions.setSynthetic(constructor, true);
				EObject primarySourceElement = associations.getPrimarySourceElement(element);
				if (primarySourceElement != null) {
					associator.associate(primarySourceElement, constructor);
				}
				element.getMembers().add(constructor);
			}
		}
	}

	protected void ensureSuperTypeObject(JvmDeclaredType element) {
		if (element.getSuperTypes().isEmpty()) {
			JvmTypeReference objectType = references.getTypeForName(Object.class, element);
			if (objectType != null)
				element.getSuperTypes().add(objectType);
		}
	}

	/**
	 * @since 2.8
	 */
	protected void addAnnotations(JvmDeclaredType jvmType) {
		if (jvmType.getDeclaringType() == null) {
			GeneratorConfig generatorConfig = generatorConfigProvider.get(jvmType);
			boolean generateSuppressWarnings = !(jvmType instanceof JvmAnnotationType)
					&& generatorConfig.isGenerateSyntheticSuppressWarnings()
					&& annotationLookup.findAnnotation(jvmType, SuppressWarnings.class) == null
					&& references.findDeclaredType(SuppressWarnings.class, jvmType) instanceof JvmAnnotationType;
			JvmType generatedJvmType = references.findDeclaredType(Generated.class, jvmType);
			boolean generateGenerated = generatorConfig.isGenerateGeneratedAnnotation()
					&& generatedJvmType instanceof JvmAnnotationType;
			if (generateSuppressWarnings || generateGenerated) {
				JvmAnnotationReferenceBuilder annotationRefBuilder = annotationRefBuilderFactory.create(jvmType.eResource().getResourceSet());
				if (generateSuppressWarnings) {
					JvmAnnotationReference annotationRef = annotationRefBuilder.annotationRef(SuppressWarnings.class, "all");
					typeExtensions.setSynthetic(annotationRef, true);
					jvmType.getAnnotations().add(annotationRef);
				}
				if (generateGenerated) {
					JvmAnnotationType generatedAnnotationType = (JvmAnnotationType) generatedJvmType;
					JvmAnnotationReference annotationRef = annotationRefBuilder.annotationRef(Generated.class);
					JvmStringAnnotationValue annotationValue = typesFactory.createJvmStringAnnotationValue();
					annotationValue.getValues().add(generator.getClass().getName());
					annotationRef.getExplicitValues().add(annotationValue);
					if (generatorConfig.isIncludeDateInGeneratedAnnotation()) {
						if (dateFormat == null) {
						    dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mmZ");
						}
						String date = dateFormat.format(new Date());
						annotationValue = typesFactory.createJvmStringAnnotationValue();
						annotationValue.setOperation(getOperation(generatedAnnotationType, "date"));
						annotationValue.getValues().add(date);
						annotationRef.getExplicitValues().add(annotationValue);
					}
					if (!Strings.isNullOrEmpty(generatorConfig.getGeneratedAnnotationComment())) {
						String transformedComment = replaceVariables(generatorConfig.getGeneratedAnnotationComment(), jvmType);
						annotationValue = typesFactory.createJvmStringAnnotationValue();
						annotationValue.setOperation(getOperation(generatedAnnotationType, "comments"));
						annotationValue.getValues().add(transformedComment);
						annotationRef.getExplicitValues().add(annotationValue);
					}
					typeExtensions.setSynthetic(annotationRef, true);
					annotationLookup.removeAnnotation(jvmType, Generated.class);
					jvmType.getAnnotations().add(annotationRef);
				}
			}
		}
	}
	
	private JvmOperation getOperation(JvmAnnotationType annotationType, String operationName) {
		for (JvmOperation operation : annotationType.getDeclaredOperations()) {
			if (operationName.equals(operation.getSimpleName()))
				return operation;
		}
		return null;
	}
	
	/**
	 * Replace the variables contained in the comment to be written to the @Generated annotation.
	 */
	protected String replaceVariables(String commentForGenerated, JvmDeclaredType jvmType) {
		String result = commentForGenerated;
		if (result.contains(GENERATED_COMMENT_VAR_SOURCE_FILE)) {
			Resource resource = jvmType.eResource();
			if (resource != null) {
				URI uri = resource.getURI();
				if (uri != null) {
					String sourceFile = uri.lastSegment();
					if (sourceFile == null)
						sourceFile = uri.toString();
					result = result.replace(GENERATED_COMMENT_VAR_SOURCE_FILE, sourceFile);
				}
			}
		}
		return result;
	}
	
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy