/** Creates a {@link PluginPropertyField} based on the given field. */ private PluginPropertyField createPluginProperty(Field field, TypeToken<?> resolvingType) throws UnsupportedTypeException { TypeToken<?> fieldType = resolvingType.resolveType(field.getGenericType()); Class<?> rawType = fieldType.getRawType(); Name nameAnnotation = field.getAnnotation(Name.class); Description descAnnotation = field.getAnnotation(Description.class); String name = nameAnnotation == null ? field.getName() : nameAnnotation.value(); String description = descAnnotation == null ? "" : descAnnotation.value(); if (rawType.isPrimitive()) { return new PluginPropertyField(name, description, rawType.getName(), true); } rawType = Primitives.unwrap(rawType); if (!rawType.isPrimitive() && !String.class.equals(rawType)) { throw new UnsupportedTypeException("Only primitive and String types are supported"); } boolean required = true; for (Annotation annotation : field.getAnnotations()) { if (annotation.annotationType().getName().endsWith(".Nullable")) { required = false; break; } } return new PluginPropertyField( name, description, rawType.getSimpleName().toLowerCase(), required); }
private List<ApplicationClass> inspectApplications(File artifactFile) throws IOException, InvalidArtifactException { List<ApplicationClass> apps = Lists.newArrayList(); Location artifactLocation = Locations.toLocation(artifactFile); Manifest manifest = BundleJarUtil.getManifest(artifactLocation); if (manifest == null) { return apps; } Attributes manifestAttributes = manifest.getMainAttributes(); if (manifestAttributes == null) { return apps; } // right now we force users to include the application main class as an attribute in their // manifest, // which forces them to have a single application class. // in the future, we may want to let users do this or maybe specify a list of classes or // a package that will be searched for applications, to allow multiple applications in a single // artifact. String mainClassName = manifestAttributes.getValue(ManifestFields.MAIN_CLASS); if (mainClassName != null) { try (CloseableClassLoader artifactClassLoader = artifactClassLoaderFactory.createClassLoader(Locations.toLocation(artifactFile))) { Object appMain = artifactClassLoader.loadClass(mainClassName).newInstance(); if (!(appMain instanceof Application)) { throw new InvalidArtifactException( String.format( "Application main class is of invalid type: %s", appMain.getClass().getName())); } Application app = (Application) appMain; TypeToken typeToken = TypeToken.of(app.getClass()); TypeToken<?> resultToken = typeToken.resolveType(Application.class.getTypeParameters()[0]); Type configType; // if the user parameterized their template, like 'xyz extends ApplicationTemplate<T>', // we can deserialize the config into that object. Otherwise it'll just be a Config if (resultToken.getType() instanceof Class) { configType = resultToken.getType(); } else { configType = Config.class; } apps.add(new ApplicationClass(mainClassName, "", schemaGenerator.generate(configType))); } catch (ClassNotFoundException e) { throw new InvalidArtifactException( String.format("Could not find Application main class %s.", mainClassName)); } catch (UnsupportedTypeException e) { throw new InvalidArtifactException( String.format("Config for Application %s has an unsupported schema.", mainClassName)); } catch (InstantiationException | IllegalAccessException e) { throw new InvalidArtifactException( String.format("Could not instantiate Application class %s.", mainClassName), e); } } return apps; }