/*
* Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Distribution License v. 1.0, which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
package org.glassfish.pfl.dynamic.codegen.impl;
import java.util.Set ;
import java.util.HashSet ;
import java.util.List ;
import java.util.ArrayList ;
import org.glassfish.pfl.dynamic.codegen.spi.ClassGenerator ;
import org.glassfish.pfl.dynamic.codegen.spi.Type ;
import org.glassfish.pfl.dynamic.codegen.spi.MethodInfo ;
import static java.lang.reflect.Modifier.* ;
Class used to generate a description of a class or interface.
An interface is an abstract class, all of whose methods are
abstract. Interfaces do not have a super class, an initializer,
or constructors. Interfaces also do not have variables.
Note: the hashCode of a ClassGeneratorImpl changes whenever a
method, constructor, or field is added, so do not put
ClassGenerators into sets or maps unless they are fully
populated.
/** Class used to generate a description of a class or interface.
* An interface is an abstract class, all of whose methods are
* abstract. Interfaces do not have a super class, an initializer,
* or constructors. Interfaces also do not have variables.
* <p>
* Note: the hashCode of a ClassGeneratorImpl changes whenever a
* method, constructor, or field is added, so do not put
* ClassGenerators into sets or maps unless they are fully
* populated.
*/
public final class ClassGeneratorImpl extends ClassInfoBase
implements ClassGenerator, Node {
private Node nodeImpl ;
private BlockStatement initializer ;
private List<MethodGenerator> methods ;
private List<MethodGenerator> constructors ;
private List<FieldGenerator> fields ;
Construct a ClassGeneratorImpl representing an interface.
/** Construct a ClassGeneratorImpl representing an interface.
*/
ClassGeneratorImpl( int modifiers, String name, List<Type> impls ) {
// Note that all interfaces must have the ABSTRACT and INTERFACE
// modifiers.
super( modifiers | ABSTRACT | INTERFACE, Type._class(name) ) ;
nodeImpl = new NodeBase( null ) ;
initializeInterface( impls ) ;
initializer = null ;
methods = new ArrayList<MethodGenerator>() ;
constructors = null ;
fields = null ;
}
Construct a ClassGeneratorImpl representing a class.
/** Construct a ClassGeneratorImpl representing a class.
*/
ClassGeneratorImpl( int modifiers, String name, Type superType,
List<Type> impls ) {
super( modifiers, Type._class( name ) ) ;
nodeImpl = new NodeBase( null ) ;
// We need the Type._class( name ) form of the class
// type in order for Type._classGenerator to function
// correctly. Later we will need the _classGenerator form
// to avoid attempts to load the class for the class that
// has not yet been completely generated, so we override
// the value of thisType here.
initializeClass( Type._classGenerator( this ), superType, impls ) ;
initializer = new BlockStatement( this ) ;
methods = new ArrayList<MethodGenerator>() ;
constructors = new ArrayList<MethodGenerator>() ;
fields = new ArrayList<FieldGenerator>() ;
}
// All node methods are delegated to nodeImpl.
public Node parent() {
return nodeImpl.parent() ;
}
public int id() {
return nodeImpl.id() ;
}
public void parent( Node node ) {
nodeImpl.parent( node ) ;
}
public <T extends Node> T getAncestor( Class<T> type ) {
return nodeImpl.getAncestor( type ) ;
}
public <T extends Node> T copy( Class<T> cls ) {
return nodeImpl.copy( cls ) ;
}
public <T extends Node> T copy( Node newParent, Class<T> cls ) {
return nodeImpl.copy( newParent, cls ) ;
}
public Object get( int index ) {
return nodeImpl.get( index ) ;
}
public void set( int index, Object obj ) {
nodeImpl.set( index, obj ) ;
}
public List<Object> attributes() {
return nodeImpl.attributes() ;
}
// End of delegation
public BlockStatement initializer() {
if (isInterface())
throw new IllegalStateException(
"An Interface does not have an initializer" ) ;
return initializer ;
}
public List<FieldGenerator> fields() {
return fields ;
}
public List<MethodGenerator> methods() {
return methods ;
}
public List<MethodGenerator> constructors() {
if (isInterface())
throw new IllegalStateException(
"An Interface does not have constructors" ) ;
return constructors ;
}
public Set<MethodInfo> constructorInfo() {
return new HashSet<MethodInfo>( constructors ) ;
}
// Every method must be added to methodInfoByName (defined in ClassInfoBase)
// AFTER it is completed. This cannot be done here in startMethod, so
// we do it in methodComplete.
public MethodGenerator startMethod( int modifiers, Type rtype, String name,
List<Type> exceptions ) {
if (isInterface() && !isAbstract(modifiers))
throw new IllegalArgumentException(
"All methods in an interface must be abstract" ) ;
MethodGenerator result = new MethodGenerator( this, modifiers, rtype,
name, exceptions ) ;
return result ;
}
// Since methods and constructors are handled largely the same way, we
// have a startConstructor method that requires a call to methodComplete
// after the constructor has been defined.
public MethodGenerator startConstructor( int modifiers,
List<Type> exceptions ) {
if (isInterface())
throw new IllegalStateException(
"Interfaces may not define constructors" ) ;
MethodGenerator result = new MethodGenerator( this, modifiers,
exceptions ) ;
return result ;
}
public void methodComplete( MethodGenerator mg ) {
mg.argsComplete() ;
if (mg.isConstructor()) {
constructors.add( mg ) ;
addConstructorInfo( mg ) ;
} else {
// Add method to the list of MethodGenerators maintained
// in the ClassGeneratorImpl API (not the same as
// methodInfoByName).
methods.add( mg ) ;
// Add method to methodInfoByName in ClassInfoBase
// after the method has been defined.
// This is required so that the hashCode value of
// the MethodGenerator does not
// change after the MethodGenerator is added to the
// Set<MethodInfo> in methodInfoByName.
addMethodInfo( mg ) ;
}
}
public FieldGenerator addField( int modifiers, Type type, String name ) {
if (isInterface())
throw new IllegalStateException(
"Interfaces may not contain data members" ) ;
if (fieldInfo().keySet().contains( name ))
throw new IllegalArgumentException( "Fields for class " + name +
" already contains field " + name ) ;
FieldGenerator var = new FieldGenerator( this, modifiers, type, name ) ;
fields.add( var ) ;
addFieldInfo( var ) ;
return var ;
}
public void accept( Visitor visitor ) {
visitor.visitClassGenerator( this ) ;
}
}