Jaxb generated sources with nullable fields - jaxb

I have kotlin project where I'm using Jaxb generated src files from xsd. The problem with these generated sources is that they have nullable fields but IDEA does not know about it. It can lead to bugs in production. To fix it we can add #Nullable annotation to all getters in generated srs-es.
How can we do it gracefully?

I made this solution, it works for me but maybe somebody knows better approuch?
Gradle kt task
tasks.register("nullableForXsdFields") {
group = "code generation"
description = "Add Nullable annotation to generated jaxb files"
actions.add {
val xjcFiles = fileTree("$buildDir/generated-sources/main/xjc")
xjcFiles.forEach { xjcFile ->
var content = xjcFile.readText()
Regex("(public) (\\w+|<|>|\\*) (get)").findAll(content).distinct()
.forEach { match ->
content = content.replace(
match.groups[0]!!.value,
match.groups[0]!!.value.replace("public ", "public #Nullable ")
)
}.run {
content = content.replace(
"import javax.xml.bind.annotation.XmlType;",
"import javax.xml.bind.annotation.XmlType;\nimport org.jetbrains.annotations.Nullable;"
)
}
xjcFile.writeBytes(content.toByteArray())
}
}
}
tasks.getByName("xjcGeneration").finalizedBy("nullableForXsdFields")
tasks.getByName("compileKotlin").dependsOn("nullableForXsdFields")
tasks.getByName("compileJava").dependsOn("nullableForXsdFields")
xjcGeneration - is my plugin to generate src from xsd

I faced the same problem, so I've created an extension for maven jaxb plugin
com.github.labai:labai-jsr305-jaxb-plugin.
This extension marks all generated packages as nullable by default, and then marks with #NotNull only those fields, which are mandatory by xsd scheme.
You can find more details how to use it with maven in github
https://github.com/labai/labai-jsr305

Related

GORM setup using Gradle and Groovy

Can anyone please share the steps to setup GORM using gradle and use the same in groovy ?
GORM for Hibernate has excellent documentation
Particularly the section of Using GORM For Hibernate Outside Grails
At minimum you need:
compile "org.grails:grails-datastore-gorm-hibernate5:6.1.10.RELEASE"
runtime "com.h2database:h2:1.4.192"
runtime "org.apache.tomcat:tomcat-jdbc:8.5.0"
runtime "org.apache.tomcat.embed:tomcat-embed-logging-log4j:8.5.0"
runtime "org.slf4j:slf4j-api:1.7.10"
Entities should go under src/main/groovy
#Entity
class Person implements GormEntity<Person> {
String firstName
String lastName
static constraints = {
firstName blank:false
lastName blank:false
}
}
and then finally bootstrap the data store somewhere:
import org.grails.orm.hibernate.HibernateDatastore
Map configuration = [
'hibernate.hbm2ddl.auto':'create-drop',
'dataSource.url':'jdbc:h2:mem:myDB'
]
HibernateDatastore datastore = new HibernateDatastore( configuration, Person)

Revit Api Load Command - Auto Reload

I'm working with the revit api, and one of its problems is that it locks the .dll once the command's run. You have to exit revit before the command can be rebuilt, very time consuming.
After some research, I came across this post on GitHub, that streams the command .dll into memory, thus hiding it from Revit. Letting you rebuild the VS project as much as you like.
The AutoReload Class impliments the revit IExteneralCommand Class which is the link into the Revit Program.
But the AutoReload class hides the actual source DLL from revit. So revit can't lock the DLL and lets one rebuilt the source file.
Only problem is I cant figure out how to implement it, and have revit execute the command. I guess my C# general knowledge is still too limited.
I created an entry in the RevitAddin.addin manifest that points to the AutoReload Method command, but nothing happens.
I've tried to follow all the comments in the posted code, but nothing seems to work; and no luck finding a contact for the developer.
Found at: https://gist.github.com/6084730.git
using System;
namespace Mine
{
// helper class
public class PluginData
{
public DateTime _creation_time;
public Autodesk.Revit.UI.IExternalCommand _instance;
public PluginData(Autodesk.Revit.UI.IExternalCommand instance)
{
_instance = instance;
}
}
//
// Base class for auto-reloading external commands that reside in other dll's
// (that Revit never knows about, and therefore cannot lock)
//
public class AutoReload : Autodesk.Revit.UI.IExternalCommand
{
// keep a static dictionary of loaded modules (so the data persists between calls to Execute)
static System.Collections.Generic.Dictionary<string, PluginData> _dictionary;
String _path; // to the dll
String _class_full_name;
public AutoReload(String path, String class_full_name)
{
if (_dictionary == null)
{
_dictionary = new System.Collections.Generic.Dictionary<string, PluginData>();
}
if (!_dictionary.ContainsKey(class_full_name))
{
PluginData data = new PluginData(null);
_dictionary.Add(class_full_name, data);
}
_path = path;
_class_full_name = class_full_name;
}
public Autodesk.Revit.UI.Result Execute(
Autodesk.Revit.UI.ExternalCommandData commandData,
ref string message,
Autodesk.Revit.DB.ElementSet elements)
{
PluginData data = _dictionary[_class_full_name];
DateTime creation_time = new System.IO.FileInfo(_path).LastWriteTime;
if (creation_time.CompareTo(data._creation_time) > 0)
{
// dll file has been modified, or this is the first time we execute this command.
data._creation_time = creation_time;
byte[] assembly_bytes = System.IO.File.ReadAllBytes(_path);
System.Reflection.Assembly assembly = System.Reflection.Assembly.Load(assembly_bytes);
foreach (Type type in assembly.GetTypes())
{
if (type.IsClass && type.FullName == _class_full_name)
{
data._instance = Activator.CreateInstance(type) as Autodesk.Revit.UI.IExternalCommand;
break;
}
}
}
// now actually call the command
return data._instance.Execute(commandData, ref message, elements);
}
}
//
// Derive a class from AutoReload for every auto-reloadable command. Hardcode the path
// to the dll and the full name of the IExternalCommand class in the constructor of the base class.
//
[Autodesk.Revit.Attributes.Transaction(Autodesk.Revit.Attributes.TransactionMode.Manual)]
[Autodesk.Revit.Attributes.Regeneration(Autodesk.Revit.Attributes.RegenerationOption.Manual)]
public class AutoReloadExample : AutoReload
{
public AutoReloadExample()
: base("C:\\revit2014plugins\\ExampleCommand.dll", "Mine.ExampleCommand")
{
}
}
}
There is an easier approach: Add-in Manager
Go to Revit Developer Center and download the Revit SDK, unzip/install it, the check at \Revit 2016 SDK\Add-In Manager folder. With this tool you can load/reload DLLs without having to modify your code.
There is also some additional information at this blog post.
this is how you can use the above code:
Create a new VS class project; name it anything (eg. AutoLoad)
Copy&Paste the above code in-between the namespace region
reference revitapi.dll & revitapiui.dll
Scroll down to AutoReloadExample class and replace the path to point
your dll
Replace "Mine.ExampleCommand" with your plugins namespace.mainclass
Build the solution
Create an .addin manifest to point this new loader (eg.
AutoLoad.dll)
your .addin should include "FullClassName" AutoLoad.AutoReloadExample
This method uses reflection to create an instance of your plugin and prevent Revit to lock your dll file! You can add more of your commands just by adding new classes like AutoReloadExample and point them with seperate .addin files.
Cheers

Custom task build order in Gradle

I have a multi-project Gradle build with a custom defind xjc task to build the jaxb generated objects and I am having issues with steps building in the correct order.
I have 3 projects, common, ref and product. ref depends on common and product depends on ref and common. The naming is important to my problem as it seems gradle does things in alphabetical order and I have stripped out some other dependencies as they do not impact the problem.
Within each project the order should be jaxb, java compile and then scala compile.
In the top level build.gradle I specify the jaxb task to be:
task jaxb() {
description 'Converts xsds to classes'
def jaxbTargetFile = file( generatedSources )
def jaxbSourceFile = file ( jaxbSourceDir )
def jaxbEpisodesFile = file ( jaxbEpisodeDir )
def bindingRootDir = file ( rootDir.getPath() + '/')
inputs.dir jaxbSourceDir
outputs.dir jaxbTargetFile
doLast {
ant.taskdef(name: 'xjc', classname: 'com.sun.tools.xjc.XJCTask', classpath: configurations.jaxb.asPath)
jaxbTargetFile.mkdirs()
jaxbEpisodesFile.mkdirs()
for ( xsd in bindingsMap) {
if (!episodeMap.containsKey(xsd.key)) {
ant.fail( "Entry no found in the episodeMap for xsd $xsd.key" )
}
def episodeFile = projectDir.getPath() + '/' + jaxbEpisodeDir + '/' + episodeMap.get(xsd.key)
println( "Processing xsd $xsd.key with binding $xsd.value producing $episodeFile" )
ant.xjc(destdir: "$jaxbTargetFile", extension: true, removeOldOutput: true) {
schema(dir:"$jaxbSourceFile", includes: "$xsd.key")
binding(dir:"$bindingRootDir" , includes: "$xsd.value")
arg(value: '-npa')
arg(value: '-verbose')
arg(value: '-episode')
arg(value: episodeFile)
}
}
}
}
In the individual build.gradle file for product I specify (with similar in ref)
dependencies {
compile project(':common')
compile project(':ref')
}
and in all three projects I specify
compileJava.dependsOn(jaxb)
when I run publish (or jar) in the product project I can see the following output:
common:jaxb
common:compileJava
common:compileScala
common:jar
product:jaxb
ref:jaxb
refcompileJava
ref:compileScala
ref:jar
product:compileJava
product:compileScala
This gives me an error because the xsd in product refers to ref and as ref has not run jaxb yet there are no episode binding files for ref and product regenerates the imported classes with the wrong package name.
How can I ensure that ref jaxb runs before product jaxb?
If your product's jaxb tasks depends on jaxb tasks for ref and common, you should define this dependency:
(in product build.gradle)
task jaxb(dependsOn: [':common:jaxb', ':ref:jaxb']) {
...
}
Set same kind dependency in ref (on commmon)

ResourceBundle MissingResourceException Linux Specific Key

I have been having this issue in iterating through an array of keys and calling the getString() method on the resource bundle. I have all the mappings I need in my bundle and for some reason one of the resource will not be fetched. This is only an issue in Linux Ubunthu 9. It works in Windows. It finds all the resources up until my "item" resource which is mapped correctly. As stated above I use the same jar on bot os's. All my resources work except this single key. I have tried changing the key and this resource, but it keeps throwing the MissingResourceException. My classpath is correct otherwise my other keys would not function. I have no idea what could be causing this. I have also tried reordering my bundle - no luck.
Any input would be appreciated.
String cols = new String[] {"name", "actor" , "requestor", "electronicFolder", "item", "dueOn", "finalOccurrenceOn"};
ResourceBundle rb = ResourceBundle.getBundle("application");
for (int i=0; i<cols.length; i++) {
if (rb==null) {
out.print("null");
} else {
try {
out.print(" " + rb.getString(cols[i]) + " : ");
} catch (MissingResourceException ee) {
ee.printStackTrace();
}
}
}
As stated above works perfectly in Windows, fails on item in Linnux Ubunthu. This is really an annoyance.
I found that this was working in my dev env, but not as a packaged EAR. The problem was that the included jsp utilized a bean tag. I removed this reference and utilize our custom tag similar to the bean tag and it worked.

DSL Add Root Element to Serialization

I am looking for help to achieve the following
The Diagram represents a car, users can add engine and colour
when I view the XML it looks like this:
<Car>
<Engine>BigEngine</Engine>
<Colour>Pink</Colour>
</Car>
What I would like to do is to wrap the car inside 'vehicle', i.e
<Vehicle>
<Car>
<Engine>BigEngine</Engine>
<Colour>Pink</Colour>
</Car>
</Vehicle>
I am not sure of the best way to achieve this. I want the model explorer and the generated XML to be wrapped in 'vehicle' but for all other intents and purposes the user is working with a car only
Info: Visual Studio 2010, C# and DSL SDK for 2010
I would try two different approaches:
1st: override DSL Package class DocData
In DocData.cs file and override method
protected override void OnDocumentSaved(System.EventArgs e)
and then I would create the wrapper
afterwards I'd override in DocData.cs
protected override void OnDocumentLoading(System.EventArgs e)
and before calling the base method base.OnDocumentLoading(e); i would delete from the file.
2nd: Under DSL Explorer go to XML Serialization Behaviour and set Car Domain Class "Is Custom = true".
This solution is not straightforward but it's not as complicated as it seems at the first place. You'll must define every single method but for each custom method you can call a DSL generated method called "DefaulMethod" which has the default DSL serializer behaviour.
I am currently using VS 2005, so some things might have changed...
I have fixed this by the following. I am double deriving the Car class and in the Car serializer I am doing this:
Writing the extra elements:
public partial class CarSerializer : CarSerializerBase
{
public override void Write(SerializationContext serializationContext, ModelElement element, XmlWriter writer, RootElementSettings rootElementSettings)
{
// Adds the Model and LobSystem root elements to match that required by the SharePoint BCS
writer.WriteStartElement("Garage");
writer.WriteStartElement("Cars");
base.Write(serializationContext, element, writer, rootElementSettings);
writer.WriteEndElement();
writer.WriteEndElement();
}
}
To be able to read this back in I am overriding the Car LoadModel method in the SerializationHelper and where it is getting the reader I am reading the elements until I get to Car.
....
XmlReader reader = XmlReader.Create(fileStream, settings);
reader.MoveToContent();
while (!reader.EOF && !reader.Name.Equals("Car"))
{
reader.Read();
}
reader = reader.ReadSubtree();
// using (global::System.Xml.XmlReader reader = global::System.Xml.XmlReader.Create(fileStream, settings))
using (reader)
{
....

Resources