This project is a JAVA library that assists the server in creating and providing additional information related to search criteria when clients use the search API, making it easier for clients to create search conditions.
I created this to send search metadata information about domains from the server, so that client-side developers can easily generate search filters for the respective domains. This way, it can potentially reduce the workload for client developers.
Go to 🚀 maven central repository
implementation group: 'io.github.mainmethod0126', name: 'search-condition-metadata', version: '0.1.0'
- short
implementation 'io.github.mainmethod0126:search-condition-metadata:0.1.0'
- kotlin
implementation("io.github.mainmethod0126:search-condition-metadata:0.1.0")
<dependency>
<groupId>io.github.mainmethod0126</groupId>
<artifactId>search-condition-metadata</artifactId>
<version>0.1.0</version>
</dependency>
Here is an example of metadata generation for the 'TestOrder' domain class.
The domain class intending to generate metadata must use the '@MetaData' annotation as a mandatory requirement.
public class MetaDataGeneratorTest {
@Test
@DisplayName("Generates metadata from a valid domain class")
public void testGenerator_whenNormalParam_thenSuccess() {
String result = MetaDataGenerator.generate(TestOrder.class);
System.out.println("metadata : " + result);
assertThat(result).isNotNull().isNotEmpty();
}
}
Result
metadata : [
{
"name": "description",
"type": "string",
"operators": ["=", "!=", "in", "not in", "regex", "wildcard"]
},
{
"name": "customer.user.id",
"type": "number",
"operators": ["=", "!=", ">=", "<=", ">", "<"]
},
{
"name": "customer.user.name",
"type": "string",
"operators": ["=", "!=", "in", "not in", "regex", "wildcard"]
},
{
"name": "customer.description",
"type": "string",
"operators": ["=", "!=", "in", "not in", "regex", "wildcard"]
},
{
"name": "products.name",
"type": "string",
"operators": ["=", "!=", "in", "not in", "regex", "wildcard"]
},
{
"name": "products.price",
"type": "number",
"operators": ["=", "!=", ">=", "<=", ">", "<"]
},
{
"name": "shippingInfo.productId",
"type": "number",
"operators": ["=", "!=", ">=", "<=", ">", "<"]
},
{
"name": "shippingInfo.quantity",
"type": "string",
"operators": ["=", "!=", "in", "not in", "regex", "wildcard"]
},
{
"name": "shippingInfo.wrapping.style",
"type": "string",
"operators": ["=", "!=", "in", "not in", "regex", "wildcard"]
}
]
You can use the @MetaDataField annotation when you want to use a separate value other than the one that defaults.
The metadata field annotation is only applied to the last primitive-type field of the domain object. If the annotation is added to a non-primitive type, it will not work and will be ignored.
Proper Functioning
@MetaData
public class TestUser {
@MetaDataField(name = "uuid", type = "number", operators = {"=", "!="})
private Long id;
private String name;
}
Ignored
@MetaData
public class TestOrder {
private String description;
// @MetaDataField Ignored Cases
@MetaDataField(name = "king", type = "string", operators = {"=", "!="})
private TestCustomer customer;
private List<TestProduct> products;
private Map<String, TestShippingInfo> shippingInfo;
}
Result
metadata : [
{
"name": "description",
"type": "string",
"operators": ["=", "!=", "in", "not in", "regex", "wildcard"]
},
{ "name": "customer.user.uuid", "type": "number", "operators": ["=", "!="] }, <---- The point where the @MetaDataField was applied
{
"name": "customer.user.name",
"type": "string",
"operators": ["=", "!=", "in", "not in", "regex", "wildcard"]
},
{
"name": "customer.description",
"type": "string",
"operators": ["=", "!=", "in", "not in", "regex", "wildcard"]
},
{
"name": "products.name",
"type": "string",
"operators": ["=", "!=", "in", "not in", "regex", "wildcard"]
},
{
"name": "products.price",
"type": "number",
"operators": ["=", "!=", ">=", "<=", ">", "<"]
},
{
"name": "shippingInfo.productId",
"type": "number",
"operators": ["=", "!=", ">=", "<=", ">", "<"]
},
{
"name": "shippingInfo.quantity",
"type": "string",
"operators": ["=", "!=", "in", "not in", "regex", "wildcard"]
},
{
"name": "shippingInfo.wrapping.style",
"type": "string",
"operators": ["=", "!=", "in", "not in", "regex", "wildcard"]
}
]
You can store the generated MetaData in the MetaDataContainer along with a unique key and retrieve it based on the key when needed.
@MetaData
public class Order {
@MetaDataField(name = "redefine_description", type = "number", operators = { "=", "!=", ">" })
private String description;
private Product product;
private Customer customer;
}
@SpringBootApplication
public class SpringSearchConditionMetadataGeneratorSampleApplication {
public static void main(String[] args) throws ClassNotFoundException {
SpringApplication.run(SpringSearchConditionMetadataGeneratorSampleApplication.class, args);
MetaDataContainer metaDataContainer = MetaDataContainer.getInstance();
metaDataContainer.setBasePackage("io.github.mainmethod0126.springsearchconditionmetadatageneratorsample");
metaDataContainer.scan();
// Since no separate key value was specified for the @MetaData annotation used in the Order class, it attempts to look up by the name of the Order class.
System.out.println("metadata : " + metaDataContainer.get(Order.class.getName()));
}
}
metadata :[
{
"name": "redefine_description",
"type": "number",
"operators": ["=", "!=", ">"]
},
{
"name": "product.name",
"type": "string",
"operators": ["=", "!=", "in", "not in", "regex", "wildcard"]
},
{
"name": "product.price",
"type": "number",
"operators": ["=", "!=", ">=", "<=", ">", "<"]
},
{
"name": "customer.user.id",
"type": "number",
"operators": ["=", "!=", ">=", "<=", ">", "<"]
},
{
"name": "customer.user.name",
"type": "string",
"operators": ["=", "!=", "in", "not in", "regex", "wildcard"]
},
{
"name": "customer.description",
"type": "string",
"operators": ["=", "!=", "in", "not in", "regex", "wildcard"]
}
]
@MetaData(key = "test_order")
public class Order {
@MetaDataField(name = "redefine_description", type = "number", operators = { "=", "!=", ">" })
private String description;
private Product product;
private Customer customer;
}
@SpringBootApplication
public class SpringSearchConditionMetadataGeneratorSampleApplication {
public static void main(String[] args) throws ClassNotFoundException {
SpringApplication.run(SpringSearchConditionMetadataGeneratorSampleApplication.class, args);
MetaDataContainer metaDataContainer = MetaDataContainer.getInstance();
metaDataContainer.setBasePackage("io.github.mainmethod0126.springsearchconditionmetadatageneratorsample");
metaDataContainer.scan();
// Since a separate key value was specified for the @MetaData annotation used in the Order class, it looks up by that key value.
System.out.println("metadata : " + metaDataContainer.get("test_order"));
}
}
metadata :[
{
"name": "redefine_description",
"type": "number",
"operators": ["=", "!=", ">"]
},
{
"name": "product.name",
"type": "string",
"operators": ["=", "!=", "in", "not in", "regex", "wildcard"]
},
{
"name": "product.price",
"type": "number",
"operators": ["=", "!=", ">=", "<=", ">", "<"]
},
{
"name": "customer.user.id",
"type": "number",
"operators": ["=", "!=", ">=", "<=", ">", "<"]
},
{
"name": "customer.user.name",
"type": "string",
"operators": ["=", "!=", "in", "not in", "regex", "wildcard"]
},
{
"name": "customer.description",
"type": "string",
"operators": ["=", "!=", "in", "not in", "regex", "wildcard"]
}
]