I need to accept a set of key - value pairs from my POM and use them in my Mojo. I want to maintain the input order as given by the user. My POM looks as follows right now:
<plugin>
<groupId>...</groupId>
<artifactId>text-replace-plugin</artifactId>
<version>...</version>
<executions>
<execution>
...
<configuration>
<replacements>
<property>
<name>ABCD</name>
<value>XYZ</value>
</property>
<property>
<name>XYZ</name>
<value>PQR</value>
</property>
</replacements>
...
</configuration>
</execution>
</executions>
</plugin>
I am accepting the replacements inside my Mojo as Java.util's Properties which I think implements Maps and is hence not ordered.
I've tried using LinkedHashMap instead of Properties but mojo doesn't seeem to understand it.
I also tried taking in the parameters as follows, but doesn't work:
#Parameter(property = "replacer.replacements", required = true)
private List replacements;
#Parameter(property = "replacer.replacements.property")
private Map eachPair;
this gives me an error: Error loading class 'com.training.replacer.Property'
Could you suggest me a way to achieve an ordered key-value pairs input from POM.xml? Thank you!
I abandoned using Java's Properties and converted my POM's outer replacements parameter with a list variable in my mojo - List<myClass>. I achieved this by creating my own class for key,value pair and providing the source package name in POM.xml. I just need to keep the names of my data members same as the POM's property names and Maven will populate the object's data members.
Refer - https://maven.apache.org/guides/mini/guide-configuring-plugins.html#Mapping_Complex_Objects
Related
In Spring Data JPA, when I want to write a custom query, if I specify a parameter, I send this parameter value with #Param annotation, Is it possible to get rid of #Param Annotation in Spring Data JPA Repository?
Example Query:
#Query("select u from User where u.name = :name")
User findUserByName(#Param("name") String name);
Desired Query:
#Query("select u from User where u.name = :name")
User findUserByName(String name);
Note, I don't want to use ?0 or something like that I want to use directly name parameters.
Yes, this is perfectly possible. As the Reference describes:
As of version 4, Spring fully supports Java 8’s parameter name discovery based on the -parameters compiler flag. By using this flag in your build as an alternative to debug information, you can omit the #Param annotation for named parameters.
And Stackoverflow has an example how to do that with Maven (and probably for the build tool of your choice as well):
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<fork>true</fork>
<compilerArgs>
<arg>-parameters</arg>
</compilerArgs>
</configuration>
</plugin>
</plugins>
</build>
I am using OpenAPI generator maven plugin like one below for generating Java client code for models .
<plugin>
<groupId>org.openapitools</groupId>
<artifactId>openapi-generator-maven-plugin</artifactId>
<version>4.3.1</version>
<executions>
<execution>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<inputSpec>${project.basedir}/src/main/resources/api.yaml</inputSpec>
<generatorName>java</generatorName>
<configOptions>
<sourceFolder>src/gen/java/main</sourceFolder>
</configOptions>
</configuration>
</execution>
</executions>
</plugin>
When , I generate the model classes, they get generated with usual POJO field declarations and getters and setters. But what I want to do is, instead of generating getters and setters, I want my classes to get automatically generated with Lombok annotations for Java pojos like #Getter, #Setter, #Data, etc. Is there a way to customize model generator to fit above use case requirement?
I tried to find out if there is a way. I found this discussion, where the very last comment talks about a PR, where the issue of generating models using Lombok annotations has been addressed. But I do not see any clear indication of usage or any documentation of this feature in the OpenAPI generator open source project that it has been implemented yet. So, is there any way of generating models with Lombok annotations instead of regular getters and setters today?
To complete this very old thread: Now it does support Lombok annotations.
Example taken from here
<configOptions>
<additionalModelTypeAnnotations>#lombok.Builder #lombok.NoArgsConstructor #lombok.AllArgsConstructor</additionalModelTypeAnnotations>
</configOptions>
EDIT: This answer is deprecated. See the post by #Laess3r. I'll leave this, since it is applicable for older versions of openapi generator.
openapi-generator does not yet support Lombok annotations. If you want to generate code with Lombok annotations, you need to create a custom template in mustache, as described in https://openapi-generator.tech/docs/templating/.
If you've never worked with mustache, be aware that it's somewhat hard to read, so try to keep the templates as simple as possible and make sure to add unit tests to validate the generated output. The template will look something like this:
/**
* {{#description}}{{description}}{{/description}}
*/
#Data
public class {{classname}} {{#parent}}extends {{{parent}}} {{/parent}} {
{{#vars}}
/**
* {{#description}}{{description}}{{/description}}
*/
#JsonProperty("{{#lambda.lowercase}}{{nameInSnakeCase}}{{/lambda.lowercase}}")
private {{{datatypeWithEnum}}} {{name}};
{{/vars}}
I've been able to get this working out-of-the-box using a space
separated list of annotations on models:
#lombok.experimental.SuperBuilder #lombok.external.Jacksonized
If models have readOnly set to "true" the Builder becomes the only way to make the object and #Jacksonized allows it to be serialized/deserialized. There are some limitations with inheritance (turning off requiring all required parameters in the configOptions).
When i'm generating java classes from jooq generator, i get one field deprecated :
/**
* #deprecated Unknown data type. Please define an explicit {#link org.jooq.Binding} to specify how this type should be handled. Deprecation can be turned off using <deprecationOnUnknownTypes/> in your code generator configuration.
*/
#java.lang.Deprecated
public final TableField<PositionRecord, Object> COORDINATES = createField("coordinates", org.jooq.impl.DefaultDataType.getDefaultDataType("point"), this, "");
I am not sure to know how to define the binding on my maven configuration with the "Point" type.
Any ideas ?
Edit :
<configuration>
<!-- JDBC connection parameters -->
<jdbc>
<driver>com.mysql.jdbc.Driver</driver>
<url>jdbc:mysql://localhost:3306/${jooq.generation.schema}</url>
<user>${jooq.generation.user}</user>
<password>${jooq.generation.password}</password>
</jdbc>
<!-- Generator parameters -->
<generator>
<generate>
<javaTimeTypes>true</javaTimeTypes>
</generate>
<database>
<name>org.jooq.util.mysql.MySQLDatabase</name>
<includes>.*</includes>
<dateAsTimestamp>true</dateAsTimestamp>
<!-- In case your database supports catalogs, e.g. SQL Server:
<inputCatalog>public</inputCatalog>
-->
<inputSchema>${jooq.generation.schema}</inputSchema>
</database>
<target>
<packageName>${jooq.generation.package}</packageName>
<directory>target/generated-sources/jooq</directory>
</target>
</generator>
</configuration>
So far i've been able to use my java classes generated by this configuration. But some fields are deprecated because of some "Data type" not recognized. So i've found out that we could kinda use "force type" and put it in the maven configuration + adding the corresponding binding to let know jooq about this data type. For instance in our case : we want to be able to reach the field "Coordinates" ( as a Point type in java). I hope i was clear enough.
You've already answered your question:
So i've found out that we could kinda use "force type" and put it in the maven configuration + adding the corresponding binding to let know jooq about this data type
That's the correct way, you need to use a data type binding: https://www.jooq.org/doc/latest/manual/code-generation/custom-data-type-bindings
Follow the instructions from the manual and you'll be fine.
I'm using Apache Olingo as an OData client for a Java SDK that I will provide for a RESTful OData API. In the SDK I want to be able to have strongly typed classes to represent the OData entities. I'm having trouble implementing this easily and thus feel like I'm missing a different strategy here.
The Olingo way seems to be to get an ODataClient object which provides the user with a bunch of useful methods for interacting with the API. The ODataClient is using a bunch of factory methods to build my request. For instance, this is the code I used to get the Customers from the Northwind sample OData service. client is an an instance of the necessary ODataClient class.
String serviceRoot = "http://services.odata.org/V4/Northwind/Northwind.svc";
URI customersUri = client.newURIBuilder(serviceRoot)
.appendEntitySetSegment("Customers").build();
ODataRetrieveResponse<ODataEntitySetIterator<ODataEntitySet, ODataEntity>> response =
client.getRetrieveRequestFactory().getEntitySetIteratorRequest(customersUri).execute();
if (response.getStatusCode() >= 400) {
log("Error");
return;
}
ODataEntitySetIterator<ODataEntitySet, ODataEntity> iterator = response.getBody();
while (iterator.hasNext()) {
ODataEntity customer = iterator.next();
log(customer.getId().toString());
}
I'd like to end up with a strongly typed entity from the iterator (i.e. Customer customer = iterator.next()). However, I'm not sure how to actually do that.
If I create a Customer class that extends ODataEntity and attempt to perform a cast such as Customer customer = (Customer) iterator.next() then I get a ClassCastException since the objects in the iterator are just ODataEntity objects and know nothing about the Customer subclass.
My next thought was to introduce generics but doing so will require what seems like a good amount of modification to the Olingo library which leads me to think that there is a better way to do this.
I'm using the development version of Apache Olingo 4 since the OData service must use OData 4.
What am I missing?
It is not really advertised, but there is nowadays a POJO generator in Olingo, in the source tree at ext / pojogen-maven-plugin. Unfortunately for using the POJOs another layer with a different programming model is added, which holds entities cached in memory and syncs with OData service on a flush operation. I would be really interested in adapting it to a more conventional request/response model based on Olingos Request Factories.
However, you could try it out. In your pom include pojogen-maven-plugin and odata-client-proxy.
The POJO generation can be triggered in the pom with
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>1.8</version>
<executions>
<execution>
<phase>process-sources</phase>
<goals>
<goal>add-source</goal>
</goals>
<configuration>
<sources>
<source>${project.build.directory}/generated-sources</source>
</sources>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.olingo</groupId>
<artifactId>pojogen-maven-plugin</artifactId>
<version>4.2.0-SNAPSHOT</version>
<configuration>
<outputDirectory>${project.build.directory}/generated-sources</outputDirectory>
<localEdm>${basedir}/src/main/resources/metadata.xml</localEdm>
<basePackage>odata.test.pojo</basePackage>
</configuration>
<executions>
<execution>
<id>v4pojoGen</id>
<phase>generate-sources</phase>
<goals>
<goal>v4pojoGen</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
For the experiment I stored the EDM Metadataof the Olingo Car example service at src/main/resources/metadata.xml. Somehow the plugin wants to create an inbetween ojc-plugin folder and I just moved the generated Java code at the proper place manually.
At that point you have a Service.java and Java interfaces for each entity or complex type in the EDM model.
You can make use of it to read some entities like this
Service<EdmEnabledODataClient> service = odata.test.pojo.Service.getV4("http://localhost:9080/odata-server-sample/cars.svc");
Container container = service.getEntityContainer(Container.class);
for (Manufacturer m : container.getManufacturers()) {
System.out.println(m.getName());
}
This is the further question to this:
How to use JPA Criteria API in JOIN
CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder();
CriteriaQuery<Company> criteria = criteriaBuilder.createQuery( Company.class );
Root<Company> companyRoot = criteria.from( Company.class );
Join<Company,Product> products = companyRoot.join("dentist");
Join<Company, City> cityJoin = companyRoot.join("address.city");//Company->Address->City-city
criteria.where(criteriaBuilder.equal(products.get("category"), "dentist"), criteriaBuilder.equal(cityJoin.get("city"),"Leeds"));
A company has an address, inside the address there is City-pojo and Country-Pojo. How can I use it in JOIN? I tried to reference it with address.city but I got the error message:
The attribute [address.city] from the managed type
[EntityTypeImpl#1692700229:Company [ javaType: class
com.test.domain.Company descriptor:
RelationalDescriptor(com.test.domain.Company -->
[DatabaseTable(COMPANY)]), mappings: 16]] is not present.
If you use canonical Metamodel, you'll avoid this kind of errors.
In your code you have misused the "dentist" keyword, that's probably the cause of your error, because "dentist" is not a field in Company entity.
However, looking at how you defined your class in the other question, the way to define that join using Metamodel is this:
SetJoin<Company,Product> products = companyRoot.join(Company_.products);
As you can see, Metamodel avoids the use of strings, and so avoids a lot of runtime errors. If anyway you don't use Metamodel, try this:
SetJoin<Company,Product> products = companyRoot.join("products");
If you now want to add a predicate, i.e. something after the where, you'll write something like:
Predicate predicate = criteriaBuilder.equal(products.get(Product_.category), "dentist");
criteria.where(predicate);
If you want to add a join for the City entity:
Join<Company, City> city = companyRoot.join(Company_.city);
predicate = criteriaBuilder.and(predicate, criteriaBuilder.equal(city.get(City_.cityName), "Leeds");
criteria.where(predicate);
(supposing that the field cityName is the correct field name for your city).
Agree with #perissf.
I can't comment but the symbol "Company_" is the metadata class file which contains all the attribute name of the model class.
I strongly suggest to use metadata classes, you can autogenerate metadata classes using the maven processor plugin using org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor as processor in your configuration.
This example pom plugin xml should work it out :
<plugin>
<groupId>org.bsc.maven</groupId>
<artifactId>maven-processor-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>process</goal>
</goals>
<phase>generate-sources</phase>
<configuration>
<processors>
<processor>org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor</processor>
</processors>
</configuration>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>org.hibernate.orm</groupId>
<artifactId>hibernate-jpamodelgen</artifactId>
<version>${version.hibernate-jpamodelgen}</version>
</dependency>
</dependencies>
</plugin>