com.google.gwt.user.rebind.rpc.Shared Maven / Gradle / Ivy
/*
* Copyright 2008 Google Inc.
*
* 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.google.gwt.user.rebind.rpc;
import com.google.gwt.core.ext.BadPropertyValueException;
import com.google.gwt.core.ext.ConfigurationProperty;
import com.google.gwt.core.ext.GeneratorContext;
import com.google.gwt.core.ext.PropertyOracle;
import com.google.gwt.core.ext.SelectionProperty;
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.typeinfo.JArrayType;
import com.google.gwt.core.ext.typeinfo.JClassType;
import com.google.gwt.core.ext.typeinfo.JParameterizedType;
import com.google.gwt.core.ext.typeinfo.JPrimitiveType;
import com.google.gwt.core.ext.typeinfo.JType;
import java.util.Collections;
import java.util.HashSet;
import java.util.Locale;
import java.util.Set;
class Shared {
/**
* Property used to control whether or not the RPC system will serialize final fields.
*/
private static final String RPC_PROP_SERIALIZE_FINAL_FIELDS = "rpc.XserializeFinalFields";
/**
* Property used to control whether or not the RPC system will emit warnings
* when a type has final fields.
*/
public static final String RPC_PROP_SUPPRESS_NON_STATIC_FINAL_FIELD_WARNINGS =
"gwt.suppressNonStaticFinalFieldWarnings";
/**
* Multi-valued configuration property used to list classes that are
* (potentially) enhanced with server-only fields, to be handled specially by
* RPC.
*/
public static final String RPC_ENHANCED_CLASSES = "rpc.enhancedClasses";
/**
* Capitalizes a name.
*
* @param name the string to be capitalized
* @return the capitalized string
*/
static String capitalize(String name) {
return name.substring(0, 1).toUpperCase(Locale.US) + name.substring(1);
}
/**
* Returns a Set of names of classes that may be enhanced with extra
* server-only fields.
*
* @param propertyOracle The propertyOracle used to access the relevant
* configuration property.
* @return a Set of Strings, or null.
*/
static Set getEnhancedTypes(PropertyOracle propertyOracle) {
try {
ConfigurationProperty prop = propertyOracle.getConfigurationProperty(RPC_ENHANCED_CLASSES);
return Collections.unmodifiableSet(new HashSet(prop.getValues()));
} catch (BadPropertyValueException e) {
return null;
}
}
static String getStreamReadMethodNameFor(JType type) {
return "read" + getCallSuffix(type);
}
static String getStreamWriteMethodNameFor(JType type) {
return "write" + getCallSuffix(type);
}
/**
* Returns true
if final field should be serialized.
*/
static boolean shouldSerializeFinalFields(TreeLogger logger,
GeneratorContext context) {
return getBooleanProperty(logger, context.getPropertyOracle(),
RPC_PROP_SERIALIZE_FINAL_FIELDS, false);
}
/**
* Returns true
if warnings should not be emitted for final
* fields in serializable types.
*/
static boolean shouldSuppressNonStaticFinalFieldWarnings(TreeLogger logger,
GeneratorContext context) {
return getBooleanProperty(logger, context.getPropertyOracle(),
RPC_PROP_SUPPRESS_NON_STATIC_FINAL_FIELD_WARNINGS, false);
}
/**
* Computes a good name for a class related to the specified type, such that
* the computed name can be a top-level class in the same package as the
* specified type.
*
*
* This method does not currently check for collisions between the synthesized
* name and an existing top-level type in the same package. It is actually
* tricky to do so, because on subsequent runs, we'll view our own generated
* classes as collisions. There's probably some trick we can use in the future
* to make it totally bulletproof.
*
*
* @param type the name of the base type, whose name will be built upon to
* synthesize a new type name
* @param suffix a suffix to be used to make the new synthesized type name
* @return an array of length 2 such that the first element is the package
* name and the second element is the synthesized class name
*/
static String[] synthesizeTopLevelClassName(JClassType type, String suffix) {
// Gets the basic name of the type. If it's a nested type, the type name
// will contains dots.
//
String className;
String packageName;
JType leafType = type.getLeafType();
if (leafType.isPrimitive() != null) {
className = leafType.getSimpleSourceName();
packageName = "com.google.gwt.user.client.rpc.core";
} else {
JClassType classOrInterface = leafType.isClassOrInterface();
assert (classOrInterface != null);
className = classOrInterface.getName();
packageName = classOrInterface.getPackage().getName();
}
JArrayType isArray = type.isArray();
if (isArray != null) {
className += "_Array_Rank_" + isArray.getRank();
}
// Add the meaningful suffix.
//
className += suffix;
// Make it a top-level name.
//
className = className.replace('.', '_');
return new String[] {packageName, className};
}
/**
* Determines whether a particular type needs to be cast to become its final
* type. Primitives and Strings do not, as they are read directly as the
* correct type. All other Objects need a cast, except for Object itself.
*
* @param type the type in question
* @return true
if the results of a read method must be cast,
* otherwise false
.
*/
static boolean typeNeedsCast(JType type) {
return type.isPrimitive() == null && !type.getQualifiedSourceName().equals("java.lang.String")
&& !type.getQualifiedSourceName().equals("java.lang.Object");
}
private static boolean getBooleanProperty(TreeLogger logger, PropertyOracle propertyOracle,
String propertyName, boolean defaultValue) {
try {
SelectionProperty prop = propertyOracle.getSelectionProperty(logger, propertyName);
String propVal = prop.getCurrentValue();
if (propVal != null && propVal.length() > 0) {
return Boolean.valueOf(propVal);
}
} catch (BadPropertyValueException e) {
// Just return the default value.
}
return defaultValue;
}
/**
* Gets the suffix needed to make a call for a particular type. For example,
* the int
class needs methods named "readInt" and "writeInt".
*
* @param type the type in question
* @return the suffix of the method to call
*/
private static String getCallSuffix(JType type) {
JParameterizedType isParameterized = type.isParameterized();
if (isParameterized != null) {
return getCallSuffix(isParameterized.getRawType());
} else if (type.isPrimitive() != null) {
if (type == JPrimitiveType.BOOLEAN) {
return "Boolean";
} else if (type == JPrimitiveType.BYTE) {
return "Byte";
} else if (type == JPrimitiveType.CHAR) {
return "Char";
} else if (type == JPrimitiveType.DOUBLE) {
return "Double";
} else if (type == JPrimitiveType.FLOAT) {
return "Float";
} else if (type == JPrimitiveType.INT) {
return "Int";
} else if (type == JPrimitiveType.LONG) {
return "Long";
} else if (type == JPrimitiveType.SHORT) {
return "Short";
} else {
return null;
}
} else if (type.getQualifiedSourceName().equals("java.lang.String")) {
return "String";
} else {
return "Object";
}
}
}