I'm using jsonschema-generator to generate a JSON schema file based on my POJOs. Currently I'm doing it via a test that is run during the gradle build step. This works fine but it doesn't feel right as really what I'm doing is not testing anything.
I've also found this answer which details how to run it on gradle run but this is not ideal either as it will pointlessly execute this every time the application comes up but not when I build.
Therefore, is there a way to tell gradle (in build.gradle) to run a piece of Java code at build time?
For completeness, here the code I'm looking to run:
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.victools.jsonschema.generator.Option;
import com.github.victools.jsonschema.generator.OptionPreset;
import com.github.victools.jsonschema.generator.SchemaGenerator;
import com.github.victools.jsonschema.generator.SchemaGeneratorConfig;
import com.github.victools.jsonschema.generator.SchemaGeneratorConfigBuilder;
import com.mypackage.MyClass;
import org.junit.jupiter.api.Test;
import java.io.PrintWriter;
import java.util.Map;
#SuppressWarnings({"FieldCanBeLocal", "rawtypes"})
public class JsonSchemaGenerator {
private final String SCHEMA_FOLDER = "schemas/";
private final Map<Class, String> schemaToGenerate = Map.of(
MyClass.class, "my-class.schema"
);
#Test
public void generateJsonSchema() throws Exception {
SchemaGeneratorConfigBuilder configBuilder = new SchemaGeneratorConfigBuilder(new ObjectMapper(), OptionPreset.PLAIN_JSON);
SchemaGeneratorConfig config = configBuilder.with(Option.DEFINITIONS_FOR_ALL_OBJECTS).build();
SchemaGenerator generator = new SchemaGenerator(config);
for (var entry : schemaToGenerate.entrySet()) {
JsonNode jsonSchema = generator.generateSchema(entry.getKey());
PrintWriter out = new PrintWriter(SCHEMA_FOLDER + entry.getValue());
out.println(jsonSchema.toPrettyString());
out.close();
}
}
}
The JavaExec Plugin seems to meet your requirements.
This allows you to run a main() method and thereby any Java Code you want – including whatever JSON Schema generation you like.
This other answer also describes pretty much what you want to do.
Adapted from the linked documentation:
apply plugin: 'java'
task generateJsonSchema(type: JavaExec) {
classpath = sourceSets.main.runtimeClasspath
main = 'package.Main'
// arguments to pass to the application
args 'appArg1'
}
As per Jorn's comment below:
You can depend the build task on your custom task: build.dependsOn generateJsonSchema if your custom task is defined as task generateJsonSchema(type: JavaExec) { ... }
i have a scenario such as below:
pyhton file name is sir_desc.py placed into this path "E:/Program Files/Java/jdk1.8.0_92/bin/sir_desc.py"
jython-2.5 jar file placed into ext folder of java dierectory
i able to run python code by using these command from commandprompt :
C:\Python27>python
import sir_desc
sir_desc.get_url_text("http://www.tutorialspoint.com/java/")
steps to run python file
python code run successfully and return text as output
how to run python file from following java code and how i remove "sys-package-mgr : can't create package cashe dir" ??
import org.python.core.PyObject;
import org.python.core.PyString;
import org.python.util.PythonInterpreter;
public class method {
public static void main(String[] args) {
PythonInterpreter interpreter = new PythonInterpreter();
interpreter.execfile("E:/Program Files/Java/jdk1.8.0_92/bin/sir_desc.py");
PyObject str = interpreter.eval("repr(get_url_text(\"http://www.tutorialspoint.com/java/\"))");
System.out.println(str.toString());
}
}
I am trying to use a custom formatter to turn a boolean into "Yes" or "No" and have run into a roadblock.
My IDE (Eclipse) does not indicate any errors but when I try to compile I receive
[ERROR] Annotation error: cannot resolve foobar.client.formatter.YesNoFormatter - exception: ClassNotFoundException
followed by a few other exceptions that appear to stem from this exception. I understand what a ClassNotFoundException indicates however I cannot figure out why I would be getting it since, as my code shows, the YesNoFormatter class is located in foobar.client.formatter and I can access it through
GWT.log("True: " + YesNoFactory.getFormat().format(Boolean.TRUE);
I am using GXT 3.1.0 and GWT 2.6.1.
Could anybody have an idea of why I am getting this exception? The example given at http://docs.sencha.com/gxt-guides/3/utility/xtemplates/XTemplates.html doesn't mention anything (as far as I can see) about these classes needing to be in specific locations so I am at a loss.
EntryPoint:
package foobar.client;
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;
import com.google.gwt.safehtml.shared.SafeHtml;
import com.sencha.gxt.core.client.XTemplates.FormatterFactories;
import com.sencha.gxt.core.client.XTemplates.FormatterFactory;
public class TestClass implements EntryPoint {
#FormatterFactories(#FormatterFactory(factory=YesNoFactory.class, name="yesNo"))
public interface Renderer extends XTemplates {
#XTemplate(source="yesNo.html")
SafeHtml render(Boolean b);
}
#Override
public void onModuledLoad() {
GWT.log("True: " + YesNoFactory.getFormat().format(Boolean.TRUE);
Renderer r = GWT.create(Renderer.class);
Window.alert(r.render(true).asString());
}
}
YesNo:
package foobar.client.formatter;
import com.sencha.gxt.core.client.XTemplates.Formatter;
public class YesNo implements Formatter<Boolean> {
#Override
public String format(Boolean data) {
if (data == null) {
return null;
}
return (data) ? "Yes" : "No";
}
}
YesNoFactory:
package foobar.client.formatter;
public class YesNoFactory {
public static YesNo getFormat() {
return new YesNo();
}
}
in foobar
<?xml version="1.0 encoding="UTF-8"?>
<module>
<inherits name='com.google.gwt.user.User'/>
<inherits name='com.sencha.gxt.GXT'/>
<entry-point class='foobar.client.TestClass'/>
<source path='client'/>
</module>
foobar/client/yesNo.html:
{b:yesNo()}
My formatter classes (YesNo and YesNoFactory) apparently have to be in a location that gets compiled prior to compiling the client-side code. After I moved these classes to my 'shared' package - the package that houses code used by the client and server - everything worked.
This was not obvious in the XTemplates portion of the guide at http://docs.sencha.com/gxt-guides/3/utility/xtemplates/XTemplates.html which does not seem to specify where the files used for custom formatters need to be located. Maybe that should have been obvious but not to me.
A code is worth 1000 words of explaining it :-)
package jasim;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
public class JSTest {
public static void main(String[] args) throws ScriptException {
ScriptEngine jse = new ScriptEngineManager().getEngineByExtension("js");
jse.eval("println(new jasim.JSTest().toString)");
}
#Override
public String toString() {
return "JSTest Object";
}
}
This code will fail with the below exception:
Exception in thread "main" javax.script.ScriptException: sun.org.mozilla.javascript.internal.EcmaError: ReferenceError: "jasim" is not defined. (<Unknown source>#1) in <Unknown source> at line number 1
How do I import my own classes into the ScriptEngine?
After looking at the Mozilla Rhino docs, the solution is either to use:
importPackage(Packages.jasim) within the script, or to use new Packages.jasim.JSTest()
This is not so clear in the Sun docs regarding the importPackage in the ScriptingEngine docs.
The same way you import javax.script.ScriptEngine;...
Just make sure your classes are in the CLASSPATH
From Eclipse I can easily run all the JUnit tests in my application.
I would like to be able to run the tests on target systems from the application jar, without Eclipse (or Ant or Maven or any other development tool).
I can see how to run a specific test or suite from the command line.
I could manually create a suite listing all the tests in my application, but that seems error prone - I'm sure at some point I'll create a test and forget to add it to the suite.
The Eclipse JUnit plugin has a wizard to create a test suite, but for some reason it doesn't "see" my test classes. It may be looking for JUnit 3 tests, not JUnit 4 annotated tests.
I could write a tool that would automatically create the suite by scanning the source files.
Or I could write code so the application would scan it's own jar file for tests (either by naming convention or by looking for the #Test annotation).
It seems like there should be an easier way. What am I missing?
According to a recent thread on the JUnit mailing list, ClasspathSuite can collect and run all JUnit tests on the classpath. It is not precisely what you want, since it is a class-level annotation, but the source is available, so you may be able to extend its internal discovery mechanism.
I ran into a minor problem with my last solution. If I ran "all tests" from Eclipse they ran twice because they ran the individual tests AND the suite. I could have worked around that, but then I realized there was a simpler solution:
package suneido;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
public class RunAllTests {
public static void run(String jarfile) {
String[] tests = findTests(jarfile);
org.junit.runner.JUnitCore.main(tests);
}
private static String[] findTests(String jarfile) {
ArrayList<String> tests = new ArrayList<String>();
try {
JarFile jf = new JarFile(jarfile);
for (Enumeration<JarEntry> e = jf.entries(); e.hasMoreElements();) {
String name = e.nextElement().getName();
if (name.startsWith("suneido/") && name.endsWith("Test.class")
&& !name.contains("$"))
tests.add(name.replaceAll("/", ".")
.substring(0, name.length() - 6));
}
jf.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
return tests.toArray(new String[0]);
}
public static void main(String[] args) {
run("jsuneido.jar");
}
}
Based on http://burtbeckwith.com/blog/?p=52 I came up with the following. It seems to work well.
I can run it from within my code with:
org.junit.runner.JUnitCore.main("suneido.AllTestsSuite");
One weak point is that it relies on a naming convention ("Test" suffix) to identify tests. Another weak point is that the name of the jar file is hard coded.
package suneido;
import java.io.IOException;
import java.lang.reflect.Modifier;
import java.util.*;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import org.junit.runners.model.InitializationError;
/**
* Discovers all JUnit tests in a jar file and runs them in a suite.
*/
#RunWith(AllTestsSuite.AllTestsRunner.class)
public final class AllTestsSuite {
private final static String JARFILE = "jsuneido.jar";
private AllTestsSuite() {
}
public static class AllTestsRunner extends Suite {
public AllTestsRunner(final Class<?> clazz) throws InitializationError {
super(clazz, findClasses());
}
private static Class<?>[] findClasses() {
List<String> classFiles = new ArrayList<String>();
findClasses(classFiles);
List<Class<?>> classes = convertToClasses(classFiles);
return classes.toArray(new Class[classes.size()]);
}
private static void findClasses(final List<String> classFiles) {
JarFile jf;
try {
jf = new JarFile(JARFILE);
for (Enumeration<JarEntry> e = jf.entries(); e.hasMoreElements();) {
String name = e.nextElement().getName();
if (name.startsWith("suneido/") && name.endsWith("Test.class")
&& !name.contains("$"))
classFiles.add(name.replaceAll("/", ".")
.substring(0, name.length() - 6));
}
jf.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private static List<Class<?>> convertToClasses(
final List<String> classFiles) {
List<Class<?>> classes = new ArrayList<Class<?>>();
for (String name : classFiles) {
Class<?> c;
try {
c = Class.forName(name);
}
catch (ClassNotFoundException e) {
throw new AssertionError(e);
}
if (!Modifier.isAbstract(c.getModifiers())) {
classes.add(c);
}
}
return classes;
}
}
}
I have not tried this as of yet, but came across this blog recently: http://burtbeckwith.com/blog/?p=52
The author provides a class that discovers all your junits and runs them, so if you slot this in to your project it may provide the capability required?
Hope this helps.
Get the Java project and pass the project
JUnitLaunchShortcut jUnitLaunchShortcut = new JUnitLaunchShortcut();
jUnitLaunchShortcut.launch("Pass the Java Project containing JUnits Classes", "run");
You also could use ANT which has built-in task.
Write ANT script and run it on target machine.
ANT could create report as result.