How can I change the Table class names using the by extending jOOQ's DefaultGeneratorStrategy? - jooq

I am using the jooq codgen gradle plugin to change the naming convention for generated tables to include Table at the end of the class name. However, I am not sure how to distinguish a table from a schema in the generator.
My naming override is:
#Override
public String getJavaClassName(Definition definition, Mode mode) {
String result = super.getJavaClassName(definition, mode);
if (mode == Mode.DEFAULT) {
result += "Table";
}
return result;
}
Is there a way to determine If the current object extends TableImpl or maybe I need to take a different approach?

Just use instanceof checks on your definition, like this:
#Override
public String getJavaClassName(Definition definition, Mode mode) {
String result = super.getJavaClassName(definition, mode);
if (mode == Mode.DEFAULT && definition instanceof TableDefinition) {
result += "Table";
}
return result;
}

Related

Dapper Extensions custom ClassMapper isn't called on Insert()

I'm using Dapper Extensions and have defined my own custom mapper to deal with entities with composite keys.
public class MyClassMapper<T> : ClassMapper<T> where T : class
{
public MyClassMapper()
{
// Manage unmappable attributes
IList<PropertyInfo> toIgnore = typeof(T).GetProperties().Where(x => !x.CanWrite).ToList();
foreach (PropertyInfo propertyInfo in toIgnore.ToList())
{
Map(propertyInfo).Ignore();
}
// Manage keys
IList<PropertyInfo> propsWithId = typeof(T).GetProperties().Where(x => x.Name.EndsWith("Id") || x.Name.EndsWith("ID")).ToList();
PropertyInfo primaryKey = propsWithId.FirstOrDefault(x => string.Equals(x.Name, $"{nameof(T)}Id", StringComparison.CurrentCultureIgnoreCase));
if (primaryKey != null && primaryKey.PropertyType == typeof(int))
{
Map(primaryKey).Key(KeyType.Identity);
}
else if (propsWithId.Any())
{
foreach (PropertyInfo prop in propsWithId)
{
Map(prop).Key(KeyType.Assigned);
}
}
AutoMap();
}
}
I also have this test case to test my mapper:
[Test]
public void TestMyAutoMapper()
{
DapperExtensions.DapperExtensions.DefaultMapper = typeof(MyClassMapper<>);
MySubscribtionEntityWithCompositeKey entity = new MySubscribtionEntityWithCompositeKey
{
SubscriptionID = 145,
CustomerPackageID = 32
};
using (var connection = new SqlConnection(CONNECTION_STRING))
{
connection.Open();
var result = connection.Insert(entity);
var key1 = result.SubscriptionID;
var key2 = result.CustomerPackageID;
}
}
Note that I set the default mapper in the test case.
The insert fails and I notive that my customer mapper is never called. I have no documentation on the github page on the topic, so I'm not sure if there's anything else I need to do to make dapper extensions use my mapper.
Thanks in advance!
Looking at your question, you are attempting to write your own defalut class mapper derived from the existing one. I never used this approach; so I do not know why it is not working or whether it should work.
I explicitly map the classes as below:
public class Customer
{
public int CustomerID { get; set; }
public string Name { get; set; }
}
public sealed class CustomerMapper : ClassMapper<Customer>
{
public CustomerMapper()
{
Schema("dbo");
Table("Customer");
Map(x => x.CustomerID).Key(KeyType.Identity);
AutoMap();
}
}
The AutoMap() will map rest of the properties based on conventions. Please refer to these two resources for more information about mapping.
Then I call SetMappingAssemblies at the startup of the project as below:
DapperExtensions.DapperExtensions.SetMappingAssemblies(new[] { Assembly.GetExecutingAssembly() });
The GetExecutingAssembly() is used in above code because mapping classes (CustomerMapper and other) are in same assembly which is executing. If those classes are placed in other assembly, provide that assembly instead.
And that's it, it works.
To set the dialect, I call following line just below the SetMappingAssemblies:
DapperExtensions.DapperExtensions.SqlDialect = new DapperExtensions.Sql.SqlServerDialect();
Use your preferred dialect instead of SqlServerDialect.
Apparently, the solution mentioned here may help you achieve what you are actually trying to. But, I cannot be sure, as I said above, I never used it.

ADF RichSelectOneChoice get text (label)

I'm dealing with something that seems to be a trivial task but haven't found a solution: How can I access the text on a RichSelectOneChoice? I've only found the values with richSelectOneChoice.getValue() and valueChangeEvent.getNewValue()
But, how is it possible to access the actual text?
My last attempt was this:
private RichSelectOneChoice selClaim;
public void claimTypeVCL(ValueChangeEvent ve){
Map s = selClaim.getAttributes();
Object ss = s.get(ve.getNewValue());
System.out.println(ss);
}
At the moment the console output is null for the corresponding value, no matter what the choice is.
The ADF component bound to the RichSelectOneChoice object is created as a component with inner elements.
I've also tried the solution proposed by Frank Nimphius here https://community.oracle.com/thread/1050821 with the proper object type (RichSelectOneChoice) but the if clause doesn't execute because the children are not instanceof RichSelectOneChoice as suggested but rather javax.faces.component.UISelectItem and this class doesn't include the getLabel() method and running the code actually throws a wide range of errors related either to casting an object to the target type or null pointers when trying to access the label.
Solved it using the UISelectionItem object and its getItemValue() and getItemLabel() methods instead of getLabel() or getValue(), the latter of which was available but didn't render the expected result.
The working code looks like this:
public String selectedOptionStr;
public void socClaimTypeVCL(ValueChangeEvent ve){
selectedOptionStr = "";
RichSelectOneChoice sct = (RichSelectOneChoice)ve.getSource();
List childList = sct.getChildren();
for (int i = 0; i < childList.size(); i++) {
if (childList.get(i) instanceof javax.faces.component.UISelectItem) {
javax.faces.component.UISelectItem csi = (javax.faces.component.UISelectItem) childList.get(i);
if (csi.getItemValue().toString() == ve.getNewValue().toString()) {
selectedOptionStr = csi.getItemLabel();
}
}
}
}

jackson serializer cover String null to empty String("") and keep object null is null

I have tried several ways
e.g.
1.create a custom JsonSerializer, and override serialize method
#Override
public void serialize(Object value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
gen.writeString("");
}
and set the JsonSerializer to NullValueSerializer,like this:
objectMapper.getSerializerProvider().setNullValueSerializer(new NullStringSerializer());
but we can not get the Class Type from null. All null will be covert to "" , include the object.
2.if use SimpleModule
SimpleModule simpleModule = new SimpleModule("StringModule", Version.unknownVersion());
simpleModule.addSerializer(Object.class, new NullStringSerializer());
objectMapper.registerModule(simpleModule);
in the serialize method, the param value do not have any properties which is null.
from the resouce code of jackson 2.6.0 , find method serializeFields in MapSerializer.java (my object is a map) line: 545
for (Map.Entry<?,?> entry : value.entrySet()) {
Object valueElem = entry.getValue();
// First, serialize key
Object keyElem = entry.getKey();
if (keyElem == null) {
provider.findNullKeySerializer(_keyType, _property).serialize(null, gen, provider);
} else {
// One twist: is entry ignorable? If so, skip
if (ignored != null && ignored.contains(keyElem)) continue;
keySerializer.serialize(keyElem, gen, provider);
}
// And then value
if (valueElem == null) {
provider.defaultSerializeNull(gen);
} else {...}
}
when the valueElem is null, the provide just covert it to null.
and do not have any interface for me to change the strategy.
I can override MapSerializer ,but I do not know how to set the new MapSerializer to the factory.
Is there any solution?
expect your help,thank you!
find a solution :
the abstract class SerializerProvider has a method named findNullValueSerializer, which is called to get the serializer to use for serializing null values for specified property.
We can override SerializerProvider#findNullValueSerializer and match String class:
#Override
public JsonSerializer<Object> findNullValueSerializer(BeanProperty property) throws JsonMappingException {
if (property.getType().getRawClass().equals(String.class)) {
return EmptyStringSerializer.INSTANCE;
} else {
return super.findNullValueSerializer(property);
}
}
and then set SerializerProvider to our ObjectMapper instance.
done.

JAX-RS: How to automatically serialize a collection when returning a Response object?

I have a JAXB-annotated employee class:
#XmlRootElement(name = "employee")
public class Employee {
private Integer id;
private String name;
...
#XmlElement(name = "id")
public int getId() {
return this.id;
}
... // setters and getters for name, equals, hashCode, toString
}
And a JAX-RS resource object (I'm using Jersey 1.12)
#GET
#Consumes({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
#Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
#Path("/")
public List<Employee> findEmployees(
#QueryParam("name") String name,
#QueryParam("page") String pageNumber,
#QueryParam("pageSize") String pageSize) {
...
List<Employee> employees = employeeService.findEmployees(...);
return employees;
}
This endpoint works fine. I get
<employees>
<employee>
<id>2</id>
<name>Ana</name>
</employee>
</employees>
However, if I change the method to return a Response object, and put the employee list in the response body, like this:
#GET
#Consumes({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
#Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
#Path("/")
public Response findEmployees(
#QueryParam("name") String name,
#QueryParam("page") String pageNumber,
#QueryParam("pageSize") String pageSize) {
...
List<Employee> employees = employeeService.findEmployees(...);
return Response.ok().entity(employees).build();
}
the endpoint results in an HTTP 500 due to the following exception:
javax.ws.rs.WebApplicationException: com.sun.jersey.api.MessageException: A message body writer for Java class java.util.ArrayList, and Java type class java.util.ArrayList, and MIME media type application/xml was not found
In the first case, JAX-RS has obviously arranged for the proper message writer to kick in when returning a collection. It seems somewhat inconsistent that this doesn't happen when the collection is placed in the entity body. What approach can I take to get the automatic JAXB serialization of the list to happen when returning a response?
I know that I can
Just return the list from the resource method
Create a separate EmployeeList class
but was wondering whether there is a nice way to use the Response object and get the list to serialize without creating my own wrapper class.
You can wrap the List<Employee> in an instance of GenericEntity to preserve the type information:
http://docs.oracle.com/javaee/6/api/javax/ws/rs/core/GenericEntity.html
You can use GenericEntity to send the collection in the Response. You must have included appropriate marshal/unmarshal library like moxy or jaxrs-jackson.
Below is the code :
#GET
#Consumes({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
#Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
#Path("/")
public Response findEmployees(
#QueryParam("name") String name,
#QueryParam("page") String pageNumber,
#QueryParam("pageSize") String pageSize) {
...
List<Employee> employees = employeeService.findEmployees(...);
GenericEntity<List<Employee>> entity = new GenericEntity<List<Employee>>(Lists.newArrayList(employees))
return Response.ok().entity(entity).build();
}
I resolved this issue by extending the default JacksonJsonProvider class, in particular method writeTo.
Analyzing the source code of this class I found the block where the actual type is instantiated by reflection, so I've modified the source code as below:
public void writeTo(Object value, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap<String,Object> httpHeaders, OutputStream entityStream) throws IOException {
/* 27-Feb-2009, tatu: Where can we find desired encoding? Within
* HTTP headers?
*/
ObjectMapper mapper = locateMapper(type, mediaType);
JsonEncoding enc = findEncoding(mediaType, httpHeaders);
JsonGenerator jg = mapper.getJsonFactory().createJsonGenerator(entityStream, enc);
jg.disable(JsonGenerator.Feature.AUTO_CLOSE_TARGET);
// Want indentation?
if (mapper.getSerializationConfig().isEnabled(SerializationConfig.Feature.INDENT_OUTPUT)) {
jg.useDefaultPrettyPrinter();
}
// 04-Mar-2010, tatu: How about type we were given? (if any)
JavaType rootType = null;
if (genericType != null && value != null) {
/* 10-Jan-2011, tatu: as per [JACKSON-456], it's not safe to just force root
* type since it prevents polymorphic type serialization. Since we really
* just need this for generics, let's only use generic type if it's truly
* generic.
*/
if (genericType.getClass() != Class.class) { // generic types are other impls of 'java.lang.reflect.Type'
/* This is still not exactly right; should root type be further
* specialized with 'value.getClass()'? Let's see how well this works before
* trying to come up with more complete solution.
*/
//**where the magic happens**
//if the type to instantiate implements collection interface (List, Set and so on...)
//Java applies Type erasure from Generic: e.g. List<BaseRealEstate> is seen as List<?> and so List<Object>, so Jackson cannot determine #JsonTypeInfo correctly
//so, in this case we must determine at runtime the right object type to set
if(Collection.class.isAssignableFrom(type))
{
Collection<?> converted = (Collection<?>) type.cast(value);
Class<?> elementClass = Object.class;
if(converted.size() > 0)
elementClass = converted.iterator().next().getClass();
//Tell the mapper to create a collection of type passed as parameter (List, Set and so on..), containing objects determined at runtime with the previous instruction
rootType = mapper.getTypeFactory().constructCollectionType((Class<? extends Collection<?>>)type, elementClass);
}
else
rootType = mapper.getTypeFactory().constructType(genericType);
/* 26-Feb-2011, tatu: To help with [JACKSON-518], we better recognize cases where
* type degenerates back into "Object.class" (as is the case with plain TypeVariable,
* for example), and not use that.
*/
if (rootType.getRawClass() == Object.class) {
rootType = null;
}
}
}
// [JACKSON-578]: Allow use of #JsonView in resource methods.
Class<?> viewToUse = null;
if (annotations != null && annotations.length > 0) {
viewToUse = _findView(mapper, annotations);
}
if (viewToUse != null) {
// TODO: change to use 'writerWithType' for 2.0 (1.9 could use, but let's defer)
ObjectWriter viewWriter = mapper.viewWriter(viewToUse);
// [JACKSON-245] Allow automatic JSONP wrapping
if (_jsonpFunctionName != null) {
viewWriter.writeValue(jg, new JSONPObject(this._jsonpFunctionName, value, rootType));
} else if (rootType != null) {
// TODO: change to use 'writerWithType' for 2.0 (1.9 could use, but let's defer)
mapper.typedWriter(rootType).withView(viewToUse).writeValue(jg, value);
} else {
viewWriter.writeValue(jg, value);
}
} else {
// [JACKSON-245] Allow automatic JSONP wrapping
if (_jsonpFunctionName != null) {
mapper.writeValue(jg, new JSONPObject(this._jsonpFunctionName, value, rootType));
} else if (rootType != null) {
// TODO: change to use 'writerWithType' for 2.0 (1.9 could use, but let's defer)
mapper.typedWriter(rootType).writeValue(jg, value);
} else {
mapper.writeValue(jg, value);
}
}
}

EF Code First - Include(x => x.Properties.Entity) a 1 : Many association

Given a EF-Code First CTP5 entity layout like:
public class Person { ... }
which has a collection of:
public class Address { ... }
which has a single association of:
public class Mailbox { ... }
I want to do:
PersonQuery.Include(x => x.Addresses).Include("Addresses.Mailbox")
WITHOUT using a magic string. I want to do it using a lambda expression.
I am aware what I typed above will compile and will bring back all Persons matching the search criteria with their addresses and each addresses' mailbox eager loaded, but it's in a string which irritates me.
How do I do it without a string?
Thanks Stack!
For that you can use the Select method:
PersonQuery.Include(x => x.Addresses.Select(a => a.Mailbox));
You can find other examples in here and here.
For any one thats still looking for a solution to this, the Lambda includes is part of EF 4+ and it is in the System.Data.Entity namespace; examples here
http://romiller.com/2010/07/14/ef-ctp4-tips-tricks-include-with-lambda/
It is described in this post: http://www.thomaslevesque.com/2010/10/03/entity-framework-using-include-with-lambda-expressions/
Edit (By Asker for readability):
The part you are looking for is below:
public static class ObjectQueryExtensions
{
public static ObjectQuery<T> Include<T>(this ObjectQuery<T> query, Expression<Func<T, object>> selector)
{
string path = new PropertyPathVisitor().GetPropertyPath(selector);
return query.Include(path);
}
class PropertyPathVisitor : ExpressionVisitor
{
private Stack<string> _stack;
public string GetPropertyPath(Expression expression)
{
_stack = new Stack<string>();
Visit(expression);
return _stack
.Aggregate(
new StringBuilder(),
(sb, name) =>
(sb.Length > 0 ? sb.Append(".") : sb).Append(name))
.ToString();
}
protected override Expression VisitMember(MemberExpression expression)
{
if (_stack != null)
_stack.Push(expression.Member.Name);
return base.VisitMember(expression);
}
protected override Expression VisitMethodCall(MethodCallExpression expression)
{
if (IsLinqOperator(expression.Method))
{
for (int i = 1; i < expression.Arguments.Count; i++)
{
Visit(expression.Arguments[i]);
}
Visit(expression.Arguments[0]);
return expression;
}
return base.VisitMethodCall(expression);
}
private static bool IsLinqOperator(MethodInfo method)
{
if (method.DeclaringType != typeof(Queryable) && method.DeclaringType != typeof(Enumerable))
return false;
return Attribute.GetCustomAttribute(method, typeof(ExtensionAttribute)) != null;
}
}
}

Resources