Jenkins - Access JAVA "getProperties" from Groovy - java

I'm trying to use Jenkins Groovy console to modify configuration of many jobs. I need to access a field containing additional properties passed to maven by this plugin:
https://wiki.jenkins.io/display/JENKINS/Release+Plugin
So i figured out how to reach plugin classes:
for(item in Hudson.instance.items) {
if (item instanceof hudson.maven.MavenModuleSet)
{
println("\njob $item.name ");
rw = item.getBuildWrappers().get(hudson.plugins.release.ReleaseWrapper.class);
if (rw == null)
{
println("release build not configured");
}
else
{
println("\nrelease build configured");
println(rw.getParameterDefinitions());
println("\n");
println(rw.getPreBuildSteps());
println("\n");
for(step in rw.getPreBuildSteps()){
println("\nPROPERTIES: " + step.getProperties())
for(property in step.getProperties()){
println("\nPROP: " + property)
}
}
}
}
}
PROPERTIES: [settings:jenkins.mvn.DefaultSettingsProvider#307e9334,
class:class hudson.tasks.Maven, maven:null,
globalSettings:jenkins.mvn.DefaultGlobalSettingsProvider#a1e5a0,
usePrivateRepository:false,
descriptor:hudson.tasks.Maven$DescriptorImpl#5481ba47,
injectBuildVariables:true, targets:release:prepare,
requiredMonitorService:NONE]
Unfortunately properties field is a list of strings describing groovy object fields instead of data I'm looking for. It should be a simple String containing additional properties for maven.
https://javadoc.jenkins.io/hudson/tasks/Maven.html#properties
It looks like Groovy has overwritten default method and field with its magic. Is there a way to reach properties anyway?

I found it myself.
step.properties
reaches to Groovy properties.
step.#properties
reaches to the original class method.

Related

Eclipse Java Custom stream log (System.out custom)

is there a way in eclipse to have a log on a separate window?
Like System out/err but on a separate tab. It's just for debugging and then I'll remove the command.
I wouldn't want to create any other appenders in Log4j or similar.
In my case I want to keep the list of names by iterating around 100k variables.
for (VariableBean var : variables) {
if("Integer".equals(var.getType())) {
// do something
} if("String".equals(var.getType())) {
// do something
} if("Data".equals(var.getType())) {
System.....println("Data Variable: " + var);
} else {
// do something else
}
}
Thanks!

Is there any way to get all the enums classes and their respective values from a project in IntelliJ?

I need to create a list of classes declared as enum in a project in IntelliJ and, inside each one, list the respective values. Is there any automated way to accomplish this task, as it is a rather large project, with hundreds of occurrences.
Yes, you can do this using the type hierarchy view and export the entries to a file. I'm using eclipse shortcuts and I can open the type hieararchy using F4. Just make sure to filter Production files.
Example using the Guava project:
As for getting all the values for each enum, I don't think there's such a feature in Intellij, but you could probably write a script to process the exported file.
Edit
This method will print enum values using the file exported from Intellij. You might need to modify it to handle errors, etc.
private static void printEnumClassesAndValues(String file) throws IOException {
Files.lines(Path.of(file))
.filter(line -> !line.contains("java.lang"))
.map(line -> {
String[] tokens = line.replaceAll("[\\(\\),]", "").trim().split(" ");
return String.format("%s.%s", tokens[1], tokens[0]); // package + class name
})
.forEach(enumClass -> System.out.printf("%s: %s%n", enumClass, Arrays.toString(getEnumValues(enumClass))));
}
private static Enum<?>[] getEnumValues(String enumClass) {
try {
Method m = Class.forName(enumClass).getDeclaredMethod("values");
return (Enum<?>[]) m.invoke(null);
} catch (Exception ex) {
throw new RuntimeException(ex); // log or handle otherwise
}
}

Auto generate replace methods

I am running in to a lot of boilerplate code when creating language files for the application I am making. I currently have a class with all the language strings in it and then I use reflection to write these strings to the file.
What I run into quite often is that I have certain placeholders in my strings that I want to replace, for an example I might have a String like this:
public static String USER_INFO = "Username: %name% money: %balance%";
What I would like to achieve is to generate a few methods based on Annotations like I can generate getters/setters and other methods with lombok. Based on the above string I would have an annotation called Arguments(Properly should have been named Replacers or something more meaningfull) like seen here:
#Retention(RetentionPolicy.SOURCE)
#Target(ElementType.FIELD)
public #interface Arguments {
String[] value();
}
What I would like to do is to add the annotation like this:
#Arguments(
value = {"%balance%", "%name%"}
)
public static String USER_INFO = "Username: %name% - money: %balance%";
and get the following replacement methods auto generated:
public static String USER_INFONameReplacement(String name) {
return USER_INFO.replace("%name%", name);
}
public static String USER_INFOAllReplacement(String name, String balance) {
return USER_INFO.replace("%name%", name).replace("%balance%", balance);
}
public static String USER_INFOBalanceReplacement(String balance) {
return USER_INFO.replace("%balance%", balance);
}
After doing some searching I ended up trying to implement AbstractProcessor in a class like this:
#SupportedAnnotationTypes(
{"io.github.freakyville.configHelper.annotations.Arguments"})
#SupportedSourceVersion(SourceVersion.RELEASE_8)
#AutoService(Processor.class)
public class SuggestProcessor extends AbstractProcessor {
#Override
public synchronized void init(ProcessingEnvironment env) {
}
#Override
public boolean process(Set<? extends TypeElement> annoations, RoundEnvironment env) {
for (TypeElement annoation : annoations) {
Set<? extends Element> annotatedElements = env.getElementsAnnotatedWith(annoation);
Map<Boolean, List<Element>> annotatedFields = annotatedElements.stream().collect(
Collectors.partitioningBy(element ->
((ArrayType) element.asType()).getComponentType().getClass().equals(PrimitiveType.class)));
List<Element> setters = annotatedFields.get(true);
if (setters.isEmpty()) {
continue;
}
String className = ((TypeElement) setters.get(0)
.getEnclosingElement()).getQualifiedName().toString();
Map<String, List<String>> setterMap = setters.stream().collect(Collectors.toMap(
setter -> setter.getSimpleName().toString(),
setter -> Arrays.asList(setter.getAnnotation(Arguments.class).value()))
);
try {
writeBuilderFile(className, setterMap);
} catch (IOException e) {
e.printStackTrace();
}
}
return true;
}
private void writeBuilderFile(
String className, Map<String, List<String>> setterMap)
throws IOException {
String packageName = null;
int lastDot = className.lastIndexOf('.');
if (lastDot > 0) {
packageName = className.substring(0, lastDot);
}
String builderSimpleClassName = className
.substring(lastDot + 1);
JavaFileObject builderFile = processingEnv.getFiler()
.createSourceFile(className);
try (PrintWriter out = new PrintWriter(builderFile.openWriter())) {
if (packageName != null) {
out.print("package ");
out.print(packageName);
out.println(";");
out.println();
}
out.print("public class ");
out.print(builderSimpleClassName);
out.println(" {");
out.println();
setterMap.forEach((key, orgArgNames) -> {
for (int i = 0; i < orgArgNames.size(); i++) {
List<String> subList = orgArgNames.subList(0, i + 1);
List<String> argNames = subList.stream().map(v -> v.replace("%", "") + "Replacement").collect(Collectors.toList());
List<String> argsWithTypes = argNames.stream().map(v -> "String " + v).collect(Collectors.toList());
String argumentList = "(" + String.join("", argsWithTypes).substring(0, argsWithTypes.size() - 3) + ")";
String methodName;
if (orgArgNames.size() <= 1) {
methodName = key + "Replace" + subList.stream().map(v -> v.replace("%", "")).collect(Collectors.joining(""));
} else {
methodName = key + "Replace" + subList.stream().map(v -> v.replace("%", "").substring(0, 1).toUpperCase() + v.substring(1)).collect(Collectors.joining(""));
}
out.print(" public static ");
out.print(methodName);
out.print(argumentList);
out.println("{");
StringBuilder replaceSB = new StringBuilder();
replaceSB.append(key);
for (int i1 = 0; i1 < subList.size(); i1++) {
replaceSB
.append(".replace(")
.append("\"")
.append(subList.get(i))
.append("\"")
.append(",")
.append(argNames.get(i))
.append(")");
}
String replace = replaceSB.toString();
out.println("return " + replace + ";");
out.println("}");
out.println("");
}
});
out.println("}");
}
}
}
But I can't seem to get it to register it?
So my first question is, is AbstractProcessor the way to go if I want to achieve this? If not how then? if yes, then why is this not registering? I am using IntelliJ and went into settings -> build-> compiler and changed Annotation Processors to enabled and set the processor path to my SuggestProcessor
Java Annotation Processing (APT) plugins are intended for generating code based on other classes. These classes end up in a generated sources folder which is then later compiled as well. These APT plugins are discovered from the classpath / build tool configuration and ran by the IntelliJ compiler as well. Keep in mind: APT is ment to be for generated source code generation, and not at all for replacing existing classes. The only reason why Lombok is still able to do so is because they hack their way very deep into the compiler and are by that means able to manipulate the AST of classes under compilation.
Because this approach is largely controversial and error-prone with future versions of Java, it is highly unlikely that anyone will ever even attempt at building a APT-based class replacement framework or an extension of Lombok that is able to do this (weren't it for the fact that Lombok is the only tool that could be considered a "framework" for this type of APT usage and Lombok itself is not at all build in an extendible manner).
In conclusion: APT is probably the way to go, but your processor will have to create a new class rather than trying to modify an existing one.
An example of how the annotation processor should be created you can look at the following repository: https://github.com/galberola/java-apt-simple-example
I'm not sure why your current annotation processor is not associated correctly with your compiler. If you're using Maven, you could try to install the artifact for your processor locally and add it as a compile dependency to your other project. Don't forget to register the class as annotation processor with your compiler too, the example project that I referenced does this here: https://github.com/galberola/java-apt-simple-example/blob/master/example/pom.xml#L29-L31 . The same configuration can be applied to other build systems too.
There is no real way in Java of modifying classes under compilation, so if you really must have the method in the same class then this, unfortunately, means that it cannot be done.
Instead of actually creating a file and writing to it, you can modify the Abstract Syntax Tree (AST), like Lombok does. This isn't recommended and different compilers implement the AST in different ways, but you can extend the Lombok source code from github (https://github.com/rzwitserloot/lombok) and make an annotation handler if you want to. However, it is a bit hard, so make sure you really need it.
I didn't read your question correctly, sorry. To register it, you want to make a META-INF\services directory in the project that uses the annotation and the annotation processor. Within that directory, make a txt file called "javax.annotation.processing.Processor" that contains the name of the processor, like mypackage.SuggestProcessor. If you decide to use java 9, you can also declare the processor in the module-info file. The module of the processor must include "provides javax.annotation.processing.Processor with something.SuggestProcessor" and the module that uses the annotation must include "uses javax.annotation.processing.Processor." That's how javac registers annotation processors.

Error:(63, 0) Cannot set the value of read-only property 'outputFile'

I want your help. please i help.
Error:(63, 0) Cannot set the value of read-only property 'outputFile' for ApkVariantOutputImpl_Decorated{apkData=Main{type=MAIN, fullName=debug, filters=[]}} of type com.android.build.gradle.internal.api.ApkVariantOutputImpl. Open File
applicationVariants.all { variant ->
variant.outputs.each { output ->
def file = output.outputFile
output.outputFile = new File(file.parent, "kickmaterial-" + defaultConfig.versionName + ".apk")
}
}
android version is 3.0.1
please your help.
Start from gradle plugin 3.0, you can't use each() as in the documentation says:
Using the Variant API to manipulate variant outputs is broken with the
new plugin. It still works for simple tasks, such as changing the APK
name during build time, as shown below:
// If you use each() to iterate through the variant objects,
// you need to start using all(). That's because each() iterates
// through only the objects that already exist during configuration time—
// but those object don't exist at configuration time with the new model.
// However, all() adapts to the new model by picking up object as they are
// added during execution.
android.applicationVariants.all { variant ->
variant.outputs.all {
outputFileName = "${variant.name}-${variant.versionName}.apk"
}
}
So, you need to make your block code like the following:
android.applicationVariants.all { variant ->
variant.outputs.all {
outputFileName = "$kickmaterial-${variant.versionName}.apk"
}
}

Error "Cyclic linking detected" while calling a referenced object in a ScopeProvider

I am currently implementing cross-referencing for my Xtext dsl. A dsl file can contain more then one XImportSection and in some special case an XImportSection does not necessariely contain all import statements. It means I need to customize the "XImportSectionNamespaceScopeProvider" to find/build the correct XimportSection. During the implementation I figured out an unexpected behavior of the editor and/or some validation.
I used the following dsl code snipped for testing my implementation:
delta MyDelta {
adds {
package my.pkg;
import java.util.List;
public class MyClass
implements List
{
}
}
modifies my.pkg.MyClass { // (1)
adds import java.util.ArrayList;
adds superclass ArrayList<String>;
}
}
The dsl source code is described by the following grammar rules (not complete!):
AddsUnit:
{AddsUnit} 'adds' '{' unit=JavaCompilationUnit? '}';
ModifiesUnit:
'modifies' unit=[ClassOrInterface|QualifiedName] '{'
modifiesPackage=ModifiesPackage?
modifiesImports+=ModifiesImport*
modifiesSuperclass=ModifiesInheritance?
'}';
JavaCompilationUnit:
=> (annotations+=Annotation*
'package' name=QualifiedName EOL)?
importSection=XImportSection?
typeDeclarations+=ClassOrInterfaceDeclaration;
ClassOrInterfaceDeclaration:
annotations+=Annotation* modifiers+=Modifier* classOrInterface=ClassOrInterface;
ClassOrInterface: // (2a)
ClassDeclaration | InterfaceDeclaration | EnumDeclaration | AnnotationTypeDeclaration;
ClassDeclaration: // (2b)
'class' name=QualifiedName typeParameters=TypeParameters?
('extends' superClass=JvmTypeReference)?
('implements' interfaces=Typelist)?
body=ClassBody;
To provide better tool support, a ModifiesUnit references the class which is modified. This Xtext specific implementation enables hyperlinking to the class.
I am currently working on customized XImportSectionScopeProvider which provides all namespace scopes for a ModifiesUnit. The default implemantation contain a method protected List<ImportNormalizer> internalGetImportedNamespaceResolvers(EObject context, boolean ignoreCase) assumes that there is only one class-like element in a source file. But for my language there can be more then one. For this reason I have to customize it.
My idea now is the following implementation (using the Xtend programming language):
override List<ImportNormalizer> internalGetImportedNamespaceResolvers(EObject context, boolean ignoreCase) {
switch (context) {
ModifiesUnit: context.buildImportSection
default: // ... anything else
}
}
Before I startet this work, the reference worked fine and nothing unexpected happend. My goal now is to build a customized XImportSection for the ModifiesUnit which is used by Xbase to resolve references to JVM types. To do that, I need a copy of the XImportSection of the referenced ClassOrInterface. To get access to the XImportSection, I first call ModifiesUnit.getUnit(). Directly after this call is executed, the editor shows the unexpected behaviour. The minimal implementation which leads to the error looks like this:
def XImportSection buildImportSection(ModifiesUnit u) {
val ci = u.unit // Since this expression is executed, the error occurs!
// ...
}
Here, I don't know what is going internally! But it calculates an error. The editor shows the follwoing error on the qualified name at (1): "Cyclic linking detected : ModifiesUnit.unit->ModifiesUnit.unit".
My questions are: What does it mean? Why does Xtext show this error? Why does it appear if I access the referenced object?
I also figured out a strange thing there: In my first approach my code threw a NullPointerException. Ok, I tried to figure out why by printing the object ci. The result is:
org.deltaj.scoping.deltaJ.impl.ClassOrInterfaceImpl#4642f064 (eProxyURI: platform:/resource/Test/src/My.dj#xtextLink_::0.0.0.1.1::0::/2)
org.deltaj.scoping.deltaJ.impl.ClassDeclarationImpl#1c70366 (name: MyClass)
Ok, it seems to be that this method is executed two times and Xtext resolves the proxy between the first and second execution. It is fine for me as long as the received object is the correct one once. I handle it with an if-instanceof statement.
But why do I get two references there? Does it rely on the ParserRule ClassOrInterface (2a) which only is an abstract super rule of ClassDeclaration (2b)? But why is Xtext not able to resolve the reference for the ClassOrInterface?
OK, now I found a solution for my problem. During I was experimenting with my implementation, I saw that the "Problems" view stil contained unresolved references. This was the reason to rethink what my implementation did. At first, I decided to build the returned list List<ImportNormalizer directly instead of building an XImportSection which then will be converted to this list. During implementing this, I noticed that I have built the scope only for ModifiesUnitelements instead of elements which need the scope within a ModifiesUnit. This is the reason for the cyclic linking error. Now, I am building the list only if it is needed. The result is that the cyclic linking error occurs does not occur any more and all references to JVM types are resolved correctly without any errors in the problems view.
My implementation now looks like this:
class DeltaJXImportSectionNamespaceScopeProvider extends XImportSectionNamespaceScopeProvider {
override List<ImportNormalizer> internalGetImportedNamespaceResolvers(EObject context, boolean ignoreCase) {
// A scope will only be provided for elements which really need a scope. A scope is only necessary for elements
// which are siblings of a JavaCompilationUnit or a ModifiesUnit.
if (context.checkElement) { // (1)
return Collections.emptyList
}
// Finding the container which contains the import section
val container = context.jvmUnit // (2)
// For a non null container create the import normalizer list depending of returned element. If the container is
// null, no scope is needed.
return if (container != null) { // (3)
switch (container) {
JavaCompilationUnit: container.provideJcuImportNormalizerList(ignoreCase)
ModifiesUnit: container.provideMcuImportNormalizerList(ignoreCase)
}
} else {
Collections.emptyList
}
}
// Iterates upwards through the AST until a ModifiesUnit or a JavaCompilationUnit is found. (2)
def EObject jvmUnit(EObject o) {
switch (o) {
ModifiesUnit: o
JavaCompilationUnit: o
default: o.eContainer.jvmUnit
}
}
// Creates the list with all imports of a JCU (3a)
def List<ImportNormalizer> provideJcuImportNormalizerList(JavaCompilationUnit jcu, boolean ignoreCase) {
val is = jcu.importSection
return if (is != null) {
is.getImportedNamespaceResolvers(ignoreCase)
} else {
Collections.emptyList
}
}
// Creates the list of all imports of a ModifiesUnit. This implementation is similar to
// getImportedNamespaceResolvers(XImportSection, boolean) // (3b)
def List<ImportNormalizer> provideMcuImportNormalizerList(ModifiesUnit mu, boolean ignoreCase) {
val List<ImportNormalizer> result = Lists.newArrayList
result.addAll((mu.unit.jvmUnit as JavaCompilationUnit).provideJcuImportNormalizerList(ignoreCase))
for (imp : mu.modifiesImports) {
if (imp instanceof AddsImport) {
val decl = imp.importDeclaration
if (!decl.static) {
result.add(decl.transform(ignoreCase))
}
}
}
result
}
// Creates an ImportNormalizer for a given XImportSection
def ImportNormalizer transform(XImportDeclaration decl, boolean ignoreCase) {
var value = decl.importedNamespace
if (value == null) {
value = decl.importedTypeName
}
return value.createImportedNamespaceResolver(ignoreCase)
}
// Determines whether an element needs to be processed. (1)
def checkElement(EObject o) {
return o instanceof DeltaJUnit || o instanceof Delta || o instanceof AddsUnit || o instanceof ModifiesUnit ||
o instanceof RemovesUnit
}
}
As one can see, elements which do not need namespaces for correct scopes, will be ignored (1).
For each element which might need namespace for a correct scope the n-father element which directly contains the imports is determined (2).
With the correct father element the namespace list can be calculated (3) for JCU's (3a) and MU's (3b).

Categories