JAutodoc: getter comment template is merged with default comment behavior - java

I am trying to configure JAutodoc such that getter comments are generated containing only the #returns tag, like so:
/**
* #returns The non-null {#linkplain Foo foo} of this {#link IBar}.
*/
public Foo getFoo();
I have configured my getter template to produce this:
However, something must be wrong with my general JAutodoc settings, because what I get instead is a hybrid of my template and a comment parsed from the method name:
/**
* Get foo.
* #returns The non-null {#linkplain Foo foo} of this {#link IBar}.
*/
public Foo getFoo();
These are my settings:
I have removed the 'get' replacement from the replacements list, as well as unchecked the 'etter from field comment' setting as advised in this discussion, but it has not made a noticeable difference. I have also attempted to uncheck the 'Create comment from element name' setting, despite my example getter being part of an interface (in which case there is no element to get the comment from), but JAutodoc doesn't seem to care about that.
I have also tried restarting Eclipse after making each of these changes, in case that mattered. So far, nothing is working. It almost appears as if the comment behavior of getters is hard-coded. Can someone please shed some light on this?

TL;DR
JAutodoc, in its current form, can not do what you want it to do. This is because you are asking for incomplete Javadocs.
Details
(This was fun, and I hope you appreciate the effort :-)
This is a case where you are asking JAutodoc to create incomplete Javadocs. i.e. you are asking for no documentation in the Javadoc. (I personally find the repetitiveness on simple getter annoying too BTW).
The steps that JAutodoc are going through internally is:
Applying your template, so the comment looks exactly as you want - for a moment in time.
This is the bit of code that applies the template. Using your example, the member parameter below is your getFoo method and, as there is no existing comment in your code when you first apply the auto-comment, so the jdi parameter is empty (jdi.isEmpty() == true).
When the template is applied, text looks exactly as you want it too. text gets parsed just as any Javadoc comment would and returned.
From net.sf.jautodoc.source.JavadocCreator:
public JavadocInfo applyTemplate(final IMember member, final JavadocInfo jdi) throws Exception {
final JavadocInfo templateJdi = new JavadocInfo();
final String text = JAutodocPlugin.getContext().getTemplateManager().applyTemplate(member,
config.getProperties());
if (text != null && text.length() > 0) {
templateJdi.parseJavadoc(text);
}
return jdi.isEmpty() ? templateJdi : jdi.merge(templateJdi);
}
Now the JavadocInfo that was returned from applyTemplate is passed to createJavadoc. In createJavadoc the code checks if there is a comment (excluding the #params, #return, etc). As there is not any, it tries to insert some automatically from the information available. Simplistically, it just un-camel-cases the name of the method and makes that the comment.
From net.sf.jautodoc.source.JavadocCreator
public String createJavadoc(final IMethod method, final String indent, final String lineSeparator,
final JavadocInfo jdi) throws JavaModelException {
final List<String> text = jdi.getComment();
if (text.isEmpty()) {
if (config.isCreateDummyComment()) {
if (method.isConstructor()) {
text.add(Constants.JDOC_CONSTRUCTOR);
}
else if (method.isMainMethod()) {
text.add(Constants.JDOC_MAIN);
}
else {
String comment = CommentManager.createComment(config, method.getElementName(),
CommentManager.METHOD, true, true, CommentManager.FIRST_TO_UPPER);
text.add(comment + Constants.DOT);
}
}
else {
text.add("");
}
}
else {
checkForDot(text);
}
Now the code that calls the above two methods is this:
From net.sf.jautodoc.source.SourceManipulator.addJavadoc(IMember):
if (config.isCreateDummyComment()) {
jdi = javadocCreator.applyTemplate(member, jdi);
}
newJavadoc = javadocCreator.createJavadoc((IMethod) member, indent, lineDelimiter, jdi);
As you can see from these code snippets, both applying your template and creating the comment part (that you don't want!) is controlled by the same if statement config.isCreateDummyComment(). That if statement connects to the Create comment from element name option.
Examples
This issue is not happening because the method is a getter, but applies everywhere. Assume you have this bit of code:
/**
* #param myFirstParam this is important and I documented it
*/
public int doThisAndThat(int myFirstParam, int anotherParamHere) {
return 0;
}
And you apply JAutodoc to it (with Complete existing Javadoc) then you get:
With Create comment from element name unset:
/**
*
*
* #param myFirstParam this is important and I documented it
* #param anotherParamHere
* #return
*/
public int doThisAndThat(int myFirstParam, int anotherParamHere) {
return 0;
}
With Create comment from element name set:
/**
* Do this and that.
*
* #param myFirstParam this is important and I documented it
* #param anotherParamHere the another param here
* #return the int
*/
public int doThisAndThat(int myFirstParam, int anotherParamHere) {
return 0;
}
Getting the source
I couldn't find the source on any of the usual suspects (github, etc), but it is available for download here: http://sourceforge.net/projects/jautodoc/files/jautodoc/1.13.0/
So you could, if you desired, edit the source and rebuild your plug-ins. Or file a feature request with the dev.
In Conclusion
JAutodoc, in its current form, can not do what you ask it to do. However, this is essentially by design, because if you say you want to Create comment from element name automatically (internally called Create Dummy Comment) then you want fully complete Javadoc to be created for you.
Finally, keep in mind if there is no comment, then nothing appears in the method summary table and your generated Javadocs simply look incomplete.

Related

User creating multiple objects from one class during runtime -Java

So I have been looking around and reading up a lot of forums and the java documentation but I can't seem to get a solid solution for what I am trying to do.
Essentially I have a Module class as shown below:
/**
* MODULE CLASS
* This class will be the base for every Module inputed into the system
* #author George
*/
public class Module {
// -=VARIABLE DECLARATIONS=-
private String moduleName; /* String variable to store the name of the module */
private String moduleLeader; /* String variable to store the name of the module leader */
// -=GETTERS=-
public String getModuleName() {return this.moduleName;} /* Will return the name of the module */
public String getModuleLeader() {return this.moduleLeader;} /* Will return the name of the module leader */
// -=SETTERS=-
public void setModuleLeader(String l) {this.moduleLeader = l;} /* Sets the name of the module leader to the inputed name */
public void setModuleName(String n) {this.moduleName = n;} //THIS NEEDS TO BE ADDED TO DESIGN DIAGRAMS
// -=CONSTRUCTOR=-
/**
* Constructor to make a new object for the module
* #param n (NAME) - String input to set the name of the module
* #param l (LEADER) - String input to set the name of the module leader
*/
public Module(String n, String l) {
this.moduleName = n;
this.moduleLeader = l;
}
}
On my GUI, each module is represented as its own button which upon clicking will take you to the module's page using CardLayout. I also have a button where the user can add a module, this is where my issue comes into place. Obviously a Module object would be defined as:
Module newModule = new Module("name", "leader");
But how would this allow more than one object to be created. The name of the module would come from user input so there is no way I can put the name of the object in the source code and from what I have read you cannot set the object name using a variable.
Lets say for example, during runtime, the user would want to create two modules. One with the name of "Java" and one with the name of "Python". How would I go about doing this? Obviously the first object would be created just fine using the initialization above, but the name of the object would be stuck as newModule. But then it would not be able to create the second object as it cannot have two objects with the same name. I have spent some time trying to understand HashMaps to see if that could be of any use to me but quite frankly I find it quite confusing and again, I can't tell if that is the correct solution.
I hope I have worded this correctly and you can understand my problem. Any help with this would be greatly appreciated.
Thanks in advance.

Custom sequence generator for Hibernate 5

I want to create a custom sequence generator in Hibernate 5 to create a sequence per table in Postgresql. Using Hibernate 4 I did the following in my dialect:
/**
* Get the native identifier generator class.
*
* #return TableNameSequenceGenerator.
*/
#Override
Class<?> getNativeIdentifierGeneratorClass() {
TableNameSequenceGenerator
}
/**
* Creates a sequence per table instead of the default behavior of one sequence.
* From <a href='http://www.hibernate.org/296.html'>http://www.hibernate.org/296.html</a>
*/
static class TableNameSequenceGenerator extends SequenceGenerator {
/**
* {#inheritDoc}
* If the parameters do not contain a {#link SequenceGenerator#SEQUENCE} name, we
* assign one based on the table name.
*/
#Override
void configure(final Type type, final Properties params, final Dialect dialect) {
Boolean sequencePerTable = Holders.config.getProperty(SEQUENCE_PER_TABLE, Boolean, true)
if (sequencePerTable) {
if (!params.getProperty(SEQUENCE)) {
String tableName = params.getProperty(TABLE)
String schemaName = params.getProperty('schemaName')
if (schemaName) {
params.setProperty(SCHEMA, schemaName)
}
if (tableName) {
params.setProperty(SEQUENCE, "seq_${tableName}")
}
}
}
super.configure(type, params, dialect)
}
}
You can see the full code here: https://github.com/kaleidos/grails-postgresql-extensions/blob/master/src/main/groovy/net/kaleidos/hibernate/PostgresqlExtensionsDialect.groovy#L53
I'm trying to migrate to Hibernate 5 but I don't know how to configure the previous behavior. I've modified the code to extends from SequenceStyleGenerator because now SequenceGenerator has been deprecated but my code is never executed. I think this has to do with the fact that the method getNativeIdentifierGeneratorClass has also been deprecated.
I've been looking for a way to create a custom sequence but all examples I've found are focused on annotate my domain class with the sequence generator. What I'm looking for is a way to define all the sequences in a global way.
As Graeme noted (https://github.com/grails/grails-core/issues/10234) the default name of the sequence has changed in Hibernate 5, so adding
id generator: 'sequence', params: [sequence_name: 'book_seq']
to the mapping block does the trick. The problem is that it's necessary to add that to every domain class.
I'm still looking for a way to define that setting globally, maybe setting prefer_sequence_per_entity to true for every entity.
UPDATE: Finally we found a workaround to define a sequence per table globally. Just add the following to the file application.groovy:
grails.gorm.default.mapping = {
id generator: 'org.hibernate.id.enhanced.SequenceStyleGenerator', params: [prefer_sequence_per_entity: true]
}
Thanks a lot Ivan! I tried only this configuration, which worked too.
grails.gorm.default.mapping = {
id params: [prefer_sequence_per_entity: true]
}

JavaNullPointerException on calling function

I get an error when I call a function in java.
The return type is void, and I just call it and display a string inside.
Here is the call of the bugging function :
#RequestMapping(method = RequestMethod.POST)
public String findDevicesByCriteria(#Valid #ModelAttribute Device device, BindingResult bindingResult, Model uiModel) {
if (isCriteriaEmpty(device)) {
uiModel.addAttribute("criteriaEmptyWarning", "error_search_criteria_empty");
return ViewConstants.DEVICE_SEARCH_VIEW;
}
identityService.searchDevices(device.getSerialNumber(), device.getOwner().getSiteName(), device.getIpAdress(), device.getInstallDate(), device.getEndDate()); // the error come from here
return ViewConstants.DEVICE_SEARCH_VIEW;
}
The prototype in the interface of the bugging function :
/**
* Search devices.
*
* #param sn the serial number of the device
* #param site the site of it
* #param ipAdress the ip adress of it
* #param installDt the install date of it
* #param endDt the end date of it
* #return the list of device
*/
void searchDevices(String sn, String site, String ipAdress, Date installDt, Date EndDt);
And finally the function that cause problem :
public void searchDevices(String sn, String site, String ipAdress, Date installDt, Date EndDt) {
System.out.println("toto");
}
Please advice
Regards
Check that none of the following objects is null.
identityService
device
device.getOwner()
Check whether the device is null or not before accessing the values
if(device != null)
{
identityService.searchDevices(device.getSerialNumber(), device.getOwner().getSiteName(), device.getIpAdress(), device.getInstallDate(), device.getEndDate());
}
Either of identityService or service has not been initialized and therefore is null. Then you get a NullPointerException when you try to use it.
1.Plz. Confirm whether you have declared and defined the bean for identity service. (Most probably it would be #Autowired in your controller and defined as bean in your SpringBean context file) and correct the discrepancies found if any.
Whether Object device is null or not. If it is, then check your request headers and body (which leads to creation of Device object referenced by you).
It would be far more easy to pin point the issue if you could share whole your controller file(from where the function is called and debug point on line from where null pointer is thrown).

How I can write SPARQL query that uses similarity measures in Java Code

I would like to know a simple method to write this SPARQL query in Java Code:
select ?input
?string
(strlen(?match)/strlen(?string) as ?percent)
where {
values ?string { "London" "Londn" "London Fog" "Lando" "Land Ho!"
"concatenate" "catnap" "hat" "cat" "chat" "chart" "port" "part" }
values (?input ?pattern ?replacement) {
("cat" "^x[^cat]*([c]?)[^at]*([a]?)[^t]*([t]?).*$" "$1$2$3")
("Londn" "^x[^Londn]*([L]?)[^ondn]*([o]?)[^ndn]*([n]?)[^dn]*([d]?)[^n]*([n]?).*$" "$1$2$3$4$5")
}
bind( replace( concat('x',?string), ?pattern, ?replacement) as ?match )
}
order by ?pattern desc(?percent)
This code is contained in the discussion To use iSPARQL to compare values using similarity measures.
The purpose of this code is to find the resources similar to a given word on DBPedia.
This method takes into consideration that I know in advance the strings and the length of it. I would like to know how I can write this query in a parameterized method that, regardless of the word and the length of it, it returns to me the similarity measures.
Update: ARQ - Writing Property Functions is now part of the standard Jena documentation.
It looks like you'd enjoy having a syntactic extension to SPARQL that performs the more complex portions of your query. For example:
SELECT ?input ?string ?percent WHERE
{
VALUES ?string { "London" "Londn" "London Fog" "Lando" "Land Ho!"
"concatenate" "catnap" "hat" "cat" "chat" "chart" "port" "part" }
VALUES ?input { "cat" "londn" }
?input <urn:ex:fn#matches> (?string ?percent) .
}
ORDER BY DESC(?percent)
In this example, it's assumed that <urn:ex:fn#matches> is a property function that will automatically perform the matching operation and calculate the similarity.
The Jena documentation does a great job explaining how to write a custom filter function,
but (as of 07/08/2014) does little to explain how to implement a custom property function.
I will make the assumption that you can convert your answer into java code for the purpose of calculating string similarity, and focus on the implementation of a property function that can house your code.
Implementing a Property Function
Every property function is associated with a particular Context. This allows you to limit the availability of the function to be global or associated with a particular dataset.
Assuming you have an implementation of PropertyFunctionFactory (shown later), you can register the function as follows:
Registration
final PropertyFunctionRegistry reg = PropertyFunctionRegistry.chooseRegistry(ARQ.getContext());
reg.put("urn:ex:fn#matches", new MatchesPropertyFunctionFactory);
PropertyFunctionRegistry.set(ARQ.getContext(), reg);
The only difference between global and dataset-specific registration is where the Context object comes from:
final Dataset ds = DatasetFactory.createMem();
final PropertyFunctionRegistry reg = PropertyFunctionRegistry.chooseRegistry(ds.getContext());
reg.put("urn:ex:fn#matches", new MatchesPropertyFunctionFactory);
PropertyFunctionRegistry.set(ds.getContext(), reg);
MatchesPropertyFunctionFactory
public class MatchesPropertyFunctionFactory implements PropertyFunctionFactory {
#Override
public PropertyFunction create(final String uri)
{
return new PFuncSimpleAndList()
{
#Override
public QueryIterator execEvaluated(final Binding parent, final Node subject, final Node predicate, final PropFuncArg object, final ExecutionContext execCxt)
{
/* TODO insert your stuff to perform testing. Note that you'll need
* to validate that things like subject/predicate/etc are bound
*/
final boolean nonzeroPercentMatch = true; // XXX example-specific kludge
final Double percent = 0.75; // XXX example-specific kludge
if( nonzeroPercentMatch ) {
final Binding binding =
BindingFactory.binding(parent,
Var.alloc(object.getArg(1)),
NodeFactory.createLiteral(percent.toString(), XSDDatatype.XSDdecimal));
return QueryIterSingleton.create(binding, execCtx);
}
else {
return QueryIterNullIterator.create(execCtx);
}
}
};
}
}
Because the property function that we create takes a list as an argument, we use PFuncSimpleAndList as an abstract implementation. Aside from that, most of the magic that happens inside these property functions is the creation of Bindings, QueryIterators, and performing validation of the input arguments.
Validation/Closing Notes
This should be more than enough to get you going on writing your own property function, if that is where you'd like to house your string-matching logic.
What hasn't been shown is input validation. In this answer, I assume that subject and the first list argument (object.getArg(0)) are bound (Node.isConcrete()), and that the second list argument (object.getArg(1)) is not (Node.isVariable()). If your method isn't called in this manner, things would explode. Hardening the method (putting many if-else blocks with condition checks) or supporting alternative use-cases (ie: looking up values for object.getArg(0) if it is a variable) are left to the reader (because it's tedious to demonstrate, easily testable, and readily apparent during implementation).

Jena custom datatype

For a GeoSPARQL test project I want to have a custom datatype set in Jena. Howerver when I try this through the example provided at the Jena website, it still doesn't work. I get the following result:
_:b0 <http://www.opengis.net/ont/geosparql#asWKT> "POINT (52.83525867111958 6.870789811954563)^^http://www.opengis.net/ont/sf#wktLiteral "^^<java:com.hp.hpl.jena.rdf.model.impl.LiteralImpl> .
And of course I don't want the java:com.hp.hpl.jena.rdf.model.impl.LiteralImpl but http://www.opengis.net/ont/sf#wktLiteral because I wan to work with GeoSPARQL. On this page they have example data that works perfectly with my triple store and spatial index. But the above data doesn't work at all with spatial indexing.
So, my question is, I do I define a custom datatype in my RDF in Jena?
The syntax is
"POINT (52.83525867111958 6.870789811954563)"^^<http://www.opengis.net/ont/sf#wktLiteral>
I just found the answer to my question after a lot of trial and error. To add a custom RDFDatatype to my RDF model I first had to create my own class which extends BaseDatetype and which I called WktLiteral, looking like this:
public class WktLiteral extends BaseDatatype {
public static final String TypeURI = "http://www.opengis.net/ont/sf#wktLiteral";
public static final String CRS84 = "<http://www.opengis.net/def/crs/OGC/1.3/CRS84>";
public static final RDFDatatype wktLiteralType = new WktLiteral();
private WktLiteral() {
super(WktLiteral.TypeURI);
}
/**
* Convert a value of this datatype out
* to lexical form.
*/
public String unparse(Object value) {
return value.toString();
}
/**
* Parse a lexical form of this datatype to a value
*/
public Object parse(String lexicalForm) {
return new TypedValue(String.format("%s %s", WktLiteral.CRS84, lexicalForm), this.getURI());
}
/**
* Compares two instances of values of the given datatype.
* This does not allow rationals to be compared to other number
* formats, Lang tag is not significant.
*
* #param value1 First value to compare
* #param value2 Second value to compare
* #return Value to determine whether both are equal.
*/
public boolean isEqual(LiteralLabel value1, LiteralLabel value2) {
return value1.getDatatype() == value2.getDatatype()
&& value1.getValue().equals(value2.getValue());
}
Where it was quite important to return a TypedLiteral in the parse() method. After which I had to do the following to add something to my RDF model:
TypeMapper.getInstance().registerDatatype(WktLiteral.wktLiteralType);
item.addLiteral(GeoSPARQL.asWKT, ResourceFactory.createTypedLiteral(geom, WktLiteral.wktLiteralType));
Where GeoSPARQL.asWKT is the predicate in the GeoSPARQL vocabulary that I generated through schemagen. geom is the geometry object as well known text and WktLiteral.wktLiteralType is an instance of the above class.
In conclusion the result was the following (notation 3):
_:b0 <http://www.w3.org/2003/01/geo/wgs84_pos#lat_long> "POINT (51.61821756986111 5.542408362751153)" .
thus exactly what I wanted... Thanks for all the input.

Categories

Resources