I want to exclude some properties from the equals/hascode methods when generating code via Swagger/OpenApi.
Here is an example of an object defined inside the YAML file :
ExampleDTO:
type: object
properties:
id:
type: integer
format: int64
property2:
maxLength: 3
minLength: 1
pattern: '[0-9]*'
type: string
property3:
maxLength: 5
minLength: 1
pattern: '[0-9]*'
type: string
Here's the generated equals method :
#Override
public boolean equals(java.lang.Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
ExampleDTO exampleDTO = (ExampleDTO) o;
return Objects.equals(this.id, ExampleDTO.id) &&
Objects.equals(this.property2, exampleDTO.property2) &&
Objects.equals(this.property3, exampleDTO.property3);
}
The problem is that I only want the id property to be used in the equals method.
How can I do that?
Thanks!
Assuming that you are using "JavaSpring" generator, you can copy the templates from https://github.com/swagger-api/swagger-codegen/tree/master/modules/swagger-codegen/src/main/resources/JavaSpring to a local directory and modify, for example, https://github.com/swagger-api/swagger-codegen/blob/master/modules/swagger-codegen/src/main/resources/JavaSpring/pojo.mustache.
The equals method generation in the template looks like this:
#Override
public boolean equals(java.lang.Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}{{#hasVars}}
{{classname}} {{classVarName}} = ({{classname}}) o;
return {{#vars}}Objects.equals(this.{{name}}, {{classVarName}}.{{name}}){{#hasMore}} &&
{{/hasMore}}{{/vars}}{{#parent}} &&
super.equals(o){{/parent}};{{/hasVars}}{{^hasVars}}
return super.equals(o);{{/hasVars}}
}
Then when running "swagger-codegen-maven-plugin" you can pass the templateDirectory property to indicate where are located the templates.
<templateDirectory>myTemplateDir</templateDirectory>
As it is stated in the plugin homepage:
Modifying the client library format
Don't like the default swagger client syntax? Want a different
language supported? No problem! Swagger Codegen processes mustache
templates with the jmustache engine. You can modify our templates or
make your own.
You can look at
modules/swagger-codegen/src/main/resources/${your-language} for
examples. To make your own templates, create your own files and use
the -t flag to specify your template folder. It actually is that easy.
The problem with this approach is that will affect all "Pojo" objects.
If you want a more fine grained generation, then you will need to customize your own generator like extending an existing one (like JavaSpring) and specify it in
<language>com.my.package.for.GeneratorLanguage</language>
like it is informed here.
In this case you will need to change the templates so they can handle your specific processing for creating the class.
Related
I've the below method where I pass a varargs as input. I'm trying to avoid HeapPollution so besides annotating with Suppresswarnings I also wanted to make sure I validate that the class of every arg in my varargs are of the same or descendants of the class. My problem though is, if I find that the classes don't match I want to return false; With ForEach method (which returns only void I can just do a return. Is there a way to directly exit from my ForEach loop by returning false. I don't want to use the enhanced For Loop [just because I'm learning forEach :-)] but achieve what I want with the ForEach method and lambda expression. Is there a way at all?
Thanks for any help you may offer!
public final <T> boolean exists(T valueToCheck, #SuppressWarnings("unchecked") T... listOfPossibleValues) {
if (valueToCheck == null) return false;
Arrays.asList(listOfPossibleValues).forEach((T value) ->
{ if (!(valueToCheck.getClass().isAssignableFrom(value.getClass()))) return; else System.out.println(value.getClass()); });
for (T value : listOfPossibleValues){
if (value != null ) {
if (value.equals(valueToCheck)) return true;
}
}
return false;
}
I did the below and I think this solves my purpose. Ofcourse not using ForEach but using streams and a lambda expression.
return Arrays.asList(listOfPossibleValues).stream().filter(value -> !(valueToCheck.getClass().isAssignableFrom(value.getClass()))).collect(Collectors.toList()).size() > 0;
In Swashbuckle there is a setting called OrderActionGroupsBy which is supposed to change the ordering within the API, but nothing I do is working and I'm can't determine whether this is a Swashbuckle problem, or due to my IComparer any idea what I'm doing wrong?
This is setting the configurations
config.EnableSwagger(c =>
{
...
c.OrderActionGroupsBy(new CustomStringComparer());
c.GroupActionsBy(apiDesc => GroupBy(apiDesc));
...
}
This is grouping the actions by type instead of controllerName.
private static string GroupBy(ApiDescription apiDesc)
{
var controllerName = apiDesc.ActionDescriptor.ControllerDescriptor.ControllerName;
var path = apiDesc.RelativePath;
if (controllerName.Contains("Original"))
{
controllerName = controllerName.Replace("Original", "");
}
// Check if it is one of the entities if so group by that
// Otherwise group by controller
var entities = new List<string>() { "Users", "Apps", "Groups" };
var e = entities.Where(x => attr.Contains(x.ToLower())).FirstOrDefault();
if (e != null)
{
return e;
}
return controllerName;
}
This is my attempt at an IComparer I want Users first and then after that alphabetical
class CustomStringComparer : IComparer<string>
{
public int Compare(string x, string y)
{
if (x.CompareTo(y) == 0)
return 0;
if (x.CompareTo("Users") == 0)
return -1;
if (y.CompareTo("Users") == 0)
return 1;
return x.CompareTo(y);
}
}
}
This isn't working it always defaults to alphabetical no matter what I do.
Looks like this is a bug with Swashbuckle/Swagger-ui
Using OrderActionGroupsBy is correctly sorting the JSON file, but then swagger ui automatically resorts this to alphabetical order.
I have filed bugs with both Swashbuckle and swagger-ui since this seems to go against what is said in swagger-ui's doc regarding apisSorter.
Apply a sort to the API/tags list. It can be 'alpha' (sort by name) or
a function (see Array.prototype.sort() to know how sort function
works). Default is the order returned by the server unchanged.
Swashbuckle issue
swagger-ui issue
swagger-ui specific stackoverflow question
I have a property which is a Rich Text Editor in Umbraco 7.
I want to get a part of the content of this property, to be more exact, the first p tag.
How can I accomplish this in Umbraco? Is their a helper class that I can use?
There isn't a helper method that you can use out of the box but it shouldn't be too difficult to write your own.
If you're using MVC then you could write an extension to the MVC HtmlHelper as follows:
public static string GetFirstParagraph(this HtmlHelper helper, IHtmlString input)
{
if (input != null && input.ToString() != string.Empty)
{
var htmlDoc = new HtmlDocument();
htmlDoc.LoadHtml(input.ToString());
var p = htmlDoc.DocumentNode.SelectSingleNode("//p");
if (p != null)
{
return p.InnerText;
}
}
return null;
}
To call this method in your view simply type:
#Html.GetFirstParagraph(Umbraco.Field("yourPropertyAlias"))
if using the Umbraco Field method, or:
#Html.GetFirstParagraph(Model.YourProperty)
if your view is strongly typed.
If you're actually using Web Forms then you could create a razor macro and use the code above to perform the same task.
I'm trying to set up some unit tests to ensure that URLs will be mapped to the appropriate controllers and actions according to a route-table, and that the target action-method and controller exists within the relevant assembly.
The only remaining problem I'm having is testing the existence of an action-method where an ActionNameAttribute has been applied to enable dash-separated action-name mappings, e.g., a "Contact Us" form url: /contact-us maps to the ContactUs method on a Forms controller because the ContactUs method signature is defined thusly:
[ActionName("contact-us")]
public ActionResult ContactUs()
I've set up the following method, which I am running inside each test, and works for all cases where the action-method name is not redefined with ActionNameAttribute:
private static bool ActionIsDefinedOnController(string expectedActionName, string controllerName, string assemblyName)
{
var thisControllerType = Type.GetType(AssemblyQualifiedName(controllerName, assemblyName), false, true);
if (thisControllerType == null)
return false;
var allThisControllersActions = thisControllerType.GetMethods().Select(m => m.Name.ToLower());
if( allThisControllersActions.Contains(expectedActionName.ToLower()))
return true;
var methods = thisControllerType.GetMethods();
//If we've so far failed to find the method, look for methods with ActionName attributes, and check in those values:
foreach (var method in methods)
{
if (Attribute.IsDefined(method, typeof(ActionNameAttribute))
{
var a = (ActionNameAttribute) Attribute.GetCustomAttribute(method, typeof (ActionNameAttribute));
if (a.Name == expectedActionName)
return true;
}
}
return false;
}
...but whenever a method's name is redifined with ActionNameAttribute, the check Attribute.IsDefined(method, typeof(ActionNameAttribute) is failing (returns false), even when I can see the attribute in the list of custom-attributes in my debugging session:
Why is this check failing, when it should be passing?
I've been able to construct a different check:
UPDATE I had pasted in the wrong code here initially, here's the revised:
List<string> customAttributes = method.GetCustomAttributes(false).Select(a => a.ToString()).ToList();
if (customAttributes.Contains("System.Web.Mvc.ActionNameAttribute"))
{
var a = (ActionNameAttribute) Attribute.GetCustomAttribute(method, typeof (ActionNameAttribute));
if (a.Name == expectedActionName)
return true;
}
...and now my condition is catching the cases where ActionNameAttribute is applied, but now Attribute.GetCustomAttribute() returns null. So I can't check the value of the action name to compare against the expected value... arrrrgh!
I would just have:
//If we've so far failed to find the method, look for methods with ActionName attributes, and check in those values:
foreach (var method in methods)
{
var attr = method.GetCustomAttribute<System.Web.Mvc.ActionNameAttribute>();
if (attr!=null && attr.Name == expectedActionName)
{
return true;
}
}
As I said in comment, I suspect that you're picking up the wrong ActionNameAttribute in your typeof calls, so I've been explicit
I need to put a max length on my test field on my Views using ASP.NET MVC with the Entity Framework and I can't find how to get the max length of a varchar field.
Is there an easy way to get that, or any other property of a database field
Here is how i manage to do it (with an extension method on entities) :
public static int? GetMaxLength(this EntityObject entite, string nomPropriete)
{
int? result = null;
using (XEntities contexte = XEntities.GetCurrentContext())
{
var queryResult = from meta in contexte.MetadataWorkspace.GetItems(DataSpace.CSpace)
.Where(m => m.BuiltInTypeKind == BuiltInTypeKind.EntityType)
from p in (meta as EntityType).Properties
.Where(p => p.DeclaringType.Name == entite.GetType().Name
&& p.Name == nomPropriete
&& p.TypeUsage.EdmType.Name == "String")
select p.TypeUsage.Facets["MaxLength"].Value;
if (queryResult.Count() > 0)
{
result = Convert.ToInt32(queryResult.First());
}
}
return result;
}
Update
I realize that this answer doesn't directly apply to EF. At the time that I answered, there had been no answers for about 20 minutes and I thought knowing how I solved a similar problem with LINQToSQL might help. Given that the OP basically used the same technique albeit with EF properties instead, seems to indicate that I made the right choice. I'm leaving this answer here for context and for those who get here having the same problem but with LINQToSQL.
Original
I don't know about EF, but LINQToSQL entity properties are decorated with ColumnAttributes. You may be able to get the ColumnAttribute from the PropertyInfo for the property by looking at the CustomAttributesCollection. The value of this attribute would need to be parsed for length. I do that in my validator classes to make sure that I'm not going to get a SQL error by using a string that is too long for my column.
This is the method I use to extract the column length for string properties.
public static int MaximumPropertyLength( Type type, string propertyName )
{
int maximumLength = -1;
PropertyInfo info = type.GetProperty( propertyName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance );
if (info != null)
{
var attribute = info.GetCustomAttributes( typeof( ColumnAttribute ), false )
.Cast<ColumnAttribute>()
.FirstOrDefault();
if (attribute != null)
{
maximumLength = ExtractLength( attribute.DbType );
}
}
return maximumLength;
}
private static int ExtractLength( string dbType )
{
int max = int.MaxValue;
if (dbType.Contains( "(" ))
{
string[] parts = dbType.Split( new char[] { '(', ')' }, StringSplitOptions.RemoveEmptyEntries );
if (parts.Length > 1)
{
int.TryParse( parts[1], out max );
}
}
return max;
}
For EntityFramework you would need to add your own custom attributes to the classes using a Code Generator or T4 Template.
Then what tvanfosson stated above would hold true. EF does not persist this information by default.
http://blogs.msdn.com/adonet/archive/2008/01/24/customizing-code-generation-in-the-ado-net-entity-designer.aspx
Explains more of what I am talking about with your code generator. It is pretty slick I have done exactly what you are mentioning before, problem is with proprietary code so I do not have an example for you.