Get Original Field Name on GraphQL - java

I'm using https://github.com/leangen/graphql-spqr with spring-boot java application. I can reach to alias name easily but how can I reach to original fieldName?
class Food {
#GraphQLQuery(name = "aliasNameX", description = "A food's name")
private String originalName;
...
}
....
#GraphQLQuery(name = "foods") // READ ALL
#Override
public List<Food> getFoods(#GraphQLEnvironment ResolutionEnvironment env) {
DataFetchingFieldSelectionSet selectionSet = env.dataFetchingEnvironment.getSelectionSet();
List<SelectedField> fields = selectionSet.getFields();
for (SelectedField f: fields)
{
System.out.println(f.getName());
}
return foodRepository.findAll();
}
When I run this code, Output looks like with alias fields: "aliasNameX", ..., but I need original name like "originalName". Is there a way to do it?
Solved, according to:
https://github.com/leangen/graphql-spqr/issues/381

Posting my original answer here as well.
You want the underlying field names, but from a level above. Still possible, but ugly :(
for (SelectedField selectedField : env.dataFetchingEnvironment.getSelectionSet().getImmediateFields()) {
Optional<Operation> operation = Directives.getMappedOperation(selectedField.getFieldDefinition());
String javaName = operation.map(op -> ((Member) op.getTypedElement().getElement()).getName()).orElse(null);
}
Be very careful though. If there's more than one Java element exposed per GraphQL field, getTypedElement().getElement() will explode. So to be sure you'd have to call getTypedElement().getElements() (plural) instead and decide what to do. ClassUtils#getPropertyMembers might also be useful, or the ClassUtils.findXXX family of methods.
You'd basically have to do this:
List<AnnotatedElement> elements = getTypedElement().getElements();
//Look for a field and use its name
Optional<String> field = Utils.extractInstances(elements, Field.class).findFirst().map(Field::getName);
//Look for a getter and find its associated field name
Optional<String> getter = Utils.extractInstances(elements, Method.class).findFirst().map(ClassUtils::getFieldNameFromGetter);
This API might have to change in future, as SDL-based tools are proliferating, so complex directives like the ones SPQR is using are causing problems...

Related

Java class: limit instance variable to one of several possible values, depending on other instance variables

I am sorry for the vague question. I am not sure what I'm looking for here.
I have a Java class, let's call it Bar. In that class is an instance variable, let's call it foo. foo is a String.
foo cannot just have any value. There is a long list of strings, and foo must be one of them.
Then, for each of those strings in the list I would like the possibility to set some extra conditions as to whether that specific foo can belong in that specific type of Bar (depending on other instance variables in that same Bar).
What approach should I take here? Obviously, I could put the list of strings in a static class somewhere and upon calling setFoo(String s) check whether s is in that list. But that would not allow me to check for extra conditions - or I would need to put all that logic for every value of foo in the same method, which would get ugly quickly.
Is the solution to make several hundred classes for every possible value of foo and insert in each the respective (often trivial) logic to determine what types of Bar it fits? That doesn't sound right either.
What approach should I take here?
Here's a more concrete example, to make it more clear what I am looking for. Say there is a Furniture class, with a variable material, which can be lots of things, anything from mahogany to plywood. But there is another variable, upholstery, and you can make furniture containing cotton of plywood but not oak; satin furniture of oak but not walnut; other types of fabric go well with any material; et cetera.
I wouldn't suggest creating multiple classes/templates for such a big use case. This is very opinion based but I'll take a shot at answering as best as I can.
In such a case where your options can be numerous and you want to keep a maintainable code base, the best solution is to separate the values and the logic. I recommend that you store your foo values in a database. At the same time, keep your client code as clean and small as possible. So that it doesn't need to filter through the data to figure out which data is valid. You want to minimize dependency to data in your code. Think of it this way: tomorrow you might need to add a new material to your material list. Do you want to modify all your code for that? Or do you want to just add it to your database and everything magically works? Obviously the latter is a better option. Here is an example on how to design such a system. Of course, this can vary based on your use case or variables but it is a good guideline. The basic rule of thumb is: your code should have as little dependency to data as possible.
Let's say you want to create a Bar which has to have a certain foo. In this case, I would create a database for BARS which contains all the possible Bars. Example:
ID NAME FOO
1 Door 1,4,10
I will also create a database FOOS which contains the details of each foo. For example:
ID NAME PROPERTY1 PROPERTY2 ...
1 Oak Brown Soft
When you create a Bar:
Bar door = new Bar(Bar.DOOR);
in the constructor you would go to the BARS table and query the foos. Then you would query the FOOS table and load all the material and assign them to the field inside your new object.
This way whenever you create a Bar the material can be changed and loaded from DB without changing any code. You can add as many types of Bar as you can and change material properties as you goo. Your client code however doesn't change much.
You might ask why do we create a database for FOOS and refer to it's ids in the BARS table? This way, you can modify the properties of each foo as much as you want. Also you can share foos between Bars and vice versa but you only need to change the db once. cross referencing becomes a breeze. I hope this example explains the idea clearly.
You say:
Is the solution to make several hundred classes for every possible
value of foo and insert in each the respective (often trivial) logic
to determine what types of Bar it fits? That doesn't sound right
either.
Why not have separate classes for each type of Foo? Unless you need to define new types of Foo without changing the code you can model them as plain Java classes. You can go with enums as well but it does not really give you any advantage since you still need to update the enum when adding a new type of Foo.
In any case here is type safe approach that guarantees compile time checking of your rules:
public static interface Material{}
public static interface Upholstery{}
public static class Oak implements Material{}
public static class Plywood implements Material{}
public static class Cotton implements Upholstery{}
public static class Satin implements Upholstery{}
public static class Furniture<M extends Material, U extends Upholstery>{
private M matrerial = null;
private U upholstery = null;
public Furniture(M matrerial, U upholstery){
this.matrerial = matrerial;
this.upholstery = upholstery;
}
public M getMatrerial() {
return matrerial;
}
public U getUpholstery() {
return upholstery;
}
}
public static Furniture<Plywood, Cotton> cottonFurnitureWithPlywood(Plywood plywood, Cotton cotton){
return new Furniture<>(plywood, cotton);
}
public static Furniture<Oak, Satin> satinFurnitureWithOak(Oak oak, Satin satin){
return new Furniture<>(oak, satin);
}
It depends on what you really want to achieve. Creating objects and passing them around will not magically solve your domain-specific problems.
If you cannot think of any real behavior to add to your objects (except the validation), then it might make more sense to just store your data and read them into memory whenever you want. Even treat rules as data.
Here is an example:
public class Furniture {
String name;
Material material;
Upholstery upholstery;
//getters, setters, other behavior
public Furniture(String name, Material m, Upholstery u) {
//Read rule files from memory or disk and do all the checks
//Do not instantiate if validation does not pass
this.name = name;
material = m;
upholstery = u;
}
}
To specify rules, you will then create three plain text files (e.g. using csv format). File 1 will contain valid values for material, file 2 will contain valid values for upholstery, and file 3 will have a matrix format like the following:
upholstery\material plywood mahogany oak
cotton 1 0 1
satin 0 1 0
to check if a material goes with an upholstery or not, just check the corresponding row and column.
Alternatively, if you have lots of data, you can opt for a database system along with an ORM. Rule tables then can be join tables and come with extra nice features a DBMS may provide (like easy checking for duplicate values). The validation table could look something like:
MaterialID UpholsteryID Compatability_Score
plywood cotton 1
oak satin 0
The advantage of using this approach is that you quickly get a working application and you can decide what to do as you add new behavior to your application. And even if it gets way more complex in the future (new rules, new data types, etc) you can use something like the repository pattern to keep your data and business logic decoupled.
Notes about Enums:
Although the solution suggested by #Igwe Kalu solves the specific case described in the question, it is not scalable. What if you want to find what material goes with a given upholstery (the reverse case)? You will need to create another enum which does not add anything meaningful to the program, or add complex logic to your application.
This is a more detailed description of the idea I threw out there in the comment:
Keep Furniture a POJO, i.e., just hold the data, no behavior or rules implemented in it.
Implement the rules in separate classes, something along the lines of:
interface FurnitureRule {
void validate(Furniture furniture) throws FurnitureRuleException;
}
class ValidMaterialRule implements FurnitureRule {
// this you can load in whatever way suitable in your architecture -
// from enums, DB, an XML file, a JSON file, or inject via Spring, etc.
private Set<String> validMaterialNames;
#Overload
void validate(Furniture furniture) throws FurnitureRuleException {
if (!validMaterialNames.contains(furniture.getMaterial()))
throws new FurnitureRuleException("Invalid material " + furniture.getMaterial());
}
}
class UpholsteryRule implements FurnitureRule {
// Again however suitable to implement/config this
private Map<String, Set<String>> validMaterialsPerUpholstery;
#Overload
void validate(Furniture furniture) throws FurnitureRuleException {
Set<String> validMaterialNames = validMaterialsPerUpholstery.get(furniture.getUpholstery();
if (validMaterialNames != null && !validMaterialNames.contains(furniture.getMaterial()))
throws new FurnitureRuleException("Invalid material " + furniture.getMaterial() + " for upholstery " + furniture.getUpholstery());
}
}
// and more complex rules if you need to
Then have some service along the lines of FurnitureManager. It's the "gatekeeper" for all Furniture creation/updates:
class FurnitureManager {
// configure these via e.g. Spring.
private List<FurnitureRule> rules;
public void updateFurniture(Furniture furniture) throws FurnitureRuleException {
rules.forEach(rule -> rule.validate(furniture))
// proceed to persist `furniture` in the database or whatever else you do with a valid piece of furniture.
}
}
material should be of type Enum.
public enum Material {
MAHOGANY,
TEAK,
OAK,
...
}
Furthermore you can have a validator for Furniture that contains the logic which types of Furniture make sense, and then call that validator in every method that can change the material or upholstery variable (typically only your setters).
public class Furniture {
private Material material;
private Upholstery upholstery; //Could also be String depending on your needs of course
public void setMaterial(Material material) {
if (FurnitureValidator.isValidCombination(material, this.upholstery)) {
this.material = material;
}
}
...
private static class FurnitureValidator {
private static boolean isValidCombination(Material material, Upholstery upholstery) {
switch(material) {
case MAHOGANY: return upholstery != Upholstery.COTTON;
break;
//and so on
}
}
}
}
We often are oblivious of the power inherent in enum types. The Java™ Tutorials clearly states "you should use enum types any time you need to represent a fixed set of constants."
How do you simply make the best of enum in resolving the challenge you presented? - Here goes:
public enum Material {
MAHOGANY( "satin", "velvet" ),
PLYWOOD( "leather" ),
// possibly many other materials and their matching fabrics...
OAK( "some other fabric - 0" ),
WALNUT( "some other fabric - 0", "some other fabric - 1" );
private final String[] listOfSuitingFabrics;
Material( String... fabrics ) {
this.listOfSuitingFabrics = fabrics;
}
String[] getListOfSuitingFabrics() {
return Arrays.copyOf( listOfSuitingFabrics );
}
public String toString() {
return name().substring( 0, 1 ) + name().substring( 1 );
}
}
Let's test it:
public class TestMaterial {
for ( Material material : Material.values() ) {
System.out.println( material.toString() + " go well with " + material.getListOfSuitingFabrics() );
}
}
Probably the approach I'd use (because it involves the least amount of code and it's reasonably fast) is to "flatten" the hierarchical logic into a one-dimensional Set of allowed value combinations. Then when setting one of the fields, validate that the proposed new combination is valid. I'd probably just use a Set of concatenated Strings for simplicity. For the example you give above, something like this:
class Furniture {
private String wood;
private String upholstery;
/**
* Set of all acceptable values, with each combination as a String.
* Example value: "plywood:cotton"
*/
private static final Set<String> allowed = new HashSet<>();
/**
* Load allowed values in initializer.
*
* TODO: load allowed values from DB or config file
* instead of hard-wiring.
*/
static {
allowed.add("plywood:cotton");
...
}
public void setWood(String wood) {
if (!allowed.contains(wood + ":" + this.upholstery)) {
throw new IllegalArgumentException("bad combination of materials!");
}
this.wood = wood;
}
public void setUpholstery(String upholstery) {
if (!allowed.contains(this.wood + ":" + upholstery)) {
throw new IllegalArgumentException("bad combination of materials!");
}
this.upholstery = upholstery;
}
public void setMaterials(String wood, String upholstery) {
if (!allowed.contains(wood + ":" + upholstery)) {
throw new IllegalArgumentException("bad combination of materials!");
}
this.wood = wood;
this.upholstery = upholstery;
}
// getters
...
}
The disadvantage of this approach compared to other answers is that there is no compile-time type checking. For example, if you try to set the wood to plywoo instead of plywood you won’t know about your error until runtime. In practice this disadvantage is negligible since presumably the options will be chosen by a user through a UI (or through some other means), so you won’t know what they are until runtime anyway. Plus the big advantage is that the code will never have to be changed so long as you’re willing to maintain a list of allowed combinations externally. As someone with 30 years of development experience, take my word for it that this approach is far more maintainable.
With the above code, you'll need to use setMaterials before using setWood or setUpholstery, since the other field will still be null and therefore not an allowed combination. You can initialize the class's fields with default materials to avoid this if you want.

Property file based conditional patterns in java

I have a property file (a.txt) which has the values (Example values given below) like below
test1=10
test2=20
test33=34
test34=35
By reading this file, I need to produce an output like below
value = 35_20_34_10
which means => I have a pattern like test34_test2_test33_test1
Note, If the 'test33' has any value other than 34 then I need to produce the value like below
value = 35_20_10
which means => I have a pattern like test34_test2_test1
Now my problem is, every time when the customer is making the change in the logic, I am making the change in the code. So what I expect is, I want to keep the logic (pattern) in another property file so I will be sending the two inputs to the util (one input is the property file (A.txt) another input will be the 'pattern.txt'),
My util has to be compare the A.txt and the business logic 'pattern.txt' and produce the output like
value = 35_20_34_10 (or)
value = 35_20_10
If there an example for such pattern based logic as I expect?
Any predefined util / java class does this?
Any help would be Great.
thanks,
Harry
First of all, svasa's answer makes a lot of sense, but covers different level of
abstraction. I recommend you read his answer too, that pattern should
be useful.
You may wanna look at Apache Velocity and FreeMarker libraries to see how they structure their API.
Those are template engines - they usually have some abstraction of pattern or format, and abstraction of variable/value binding (or namespace, or source). You can render a template by binding it with a binding/namespace, which yields the result.
For example, you may wanna have a pattern "<a> + <b>", and binding that looks like a map: {a: "1", b: "2"}. By binding that binding to that pattern you'll get "1 + 2", when interpreting <...> as variables.
You basically load the pattern from your pattern.txt, then load your data file A.txt (for example, by treating it as properties and using Properties class) and construct binding based on these properties. You'll get your output and possibility to customize the pattern all the time.
You may call the sequences like test34_test2_test33_test1 as a pattern, let me call them as constraints when building something.
To me this problem best fits into a
builder pattern.
When building the value you want, you tell the builder that these are my constraints(pattern) and these are my original properties like below:
new MyPropertiesBuilder().setConstraints(constraints).setProperties(original).buildValue();
Details:
Set some constraints in a separate file where you specify the order of the properties and their values like :
test34=desiredvalue-could-be-empty
test2=desiredvalue-could-be-empty
test33=34
test1=desiredvalue-could-be-empty
The builder goes over the constraints in the order specified, but get the values from the original properties and build the desired string.
One way to achieve your requirement through builder pattern is to define classes like below :
Interface:
public interface IMyPropertiesBuilder
{
public void setConstraints( Properties properties );
public void setProperties( Properties properties );
public String buildValue();
}
Builder
public class MyPropertiesBuilder implements IMyPropertiesBuilder
{
private Properties constraints;
private Properties original;
#Override
public void setConstraints( Properties constraints )
{
this.constraints = constraints;
}
#Override
public String buildValue()
{
StringBuilder value = new StringBuilder();
Iterator it = constraints.keySet().iterator();
while ( it.hasNext() )
{
String key = (String) it.next();
if ( original.containsKey( key ) && constraints.getProperty( key ) != null && original.getProperty( key ).equals( constraints.getProperty( key ) ) )
{
value.append( original.getProperty( key ) );
value.append( "_" );
}
}
return value.toString();
}
#Override
public void setProperties( Properties properties )
{
this.original = properties;
}
}
User
public class MyPropertiesBuilderUser
{
private Properties original = new Properties().load(new FileInputStream("original.properties"));;
private Properties constraints = new Properties().load(new FileInputStream("constraints.properties"));
public String getValue()
{
String value = new MyPropertiesBuilder().setConstraints(constraints).setProperties(original).buildValue();
}
}

Equivalent to "Abc.class.getName()" for fields

In Java you can write:
System.out.println(Abc.class.getName());
It will always print the correct value, even if the class Abc is moved or renamed.
What is the closest you can get to that for field names?
In other words, what can I code that will always give me the "current" name of a field in a class, even if that field is renamed. Ideally, it would also fail to compile if the field is removed altogether. Or at least fail as soon as the class is accessed, during static initialisation.
I want this to simplify a "change tracking" system. It's not quite like "bean properties", because those names are NOT visible outside the class itself.
AFAIK, there is no "native" way to do this, but I'm hoping there might be some trick with annotations and/or reflection that does the job.
I'll write what I'm doing now (minimally simplified):
private static final String IS_SWAPPABLE = "isSwappable";
// ...
private boolean isSwappable;
// ...
public boolean isSwappable() {
if ((clientChanges != null) &&
clientChanges.containsKey(IS_SWAPPABLE)) {
return (Boolean) clientChanges.get(IS_SWAPPABLE);
}
return isSwappable;
}
public boolean setSwappable(final boolean newSwappable) {
if (isSwappable() != newSwappable) {
isSwappable = newSwappable;
onFieldChange(IS_SWAPPABLE, newSwappable);
return true;
}
return false;
}
What I would like is some "magic" that sets the value of IS_SWAPPABLE to "isSwappable" such that if isSwappable is renamed, then IS_SWAPPABLE will be updated appropriately.
OTOH, if there was a syntax like Abc.isSwappable (or Abc#isSwappable) or whatever, I would spare myself the constant, and just write that directly.
What I can do atm is (once) go over the constants (by using some clear naming convention), and make sure for each of them there is an instance field with the same name. But it doesn't really guaranties that IS_SWAPPABLE is used where isSwappable is used.
It looks very simple.
for (Field field : getClass().getFields()) {
System.out.println(field.getName());
}
Then you can mark fields with your own annotations and then read their values like this
for (Field field : getClass().getFields()) {
System.out.println(field.getName());
MyAnnotation annotation = field.getAnnotation( MyAnnotation.class );
System.out.println(annotation.value());
}

How to get a protobuf repeated field builder in Java?

I want to convert an object of another format into a protobuf, knowing the protobuf's Descriptors. It's easy to do for regular fields or even a nested field. But, I'm running into a problem for repeated fields.
message Foo {
optional MsgA a = 1;
repeated MsgB b = 2;
}
For "MsgA a", the code bld.getFieldBuilder(field) works:
Foo.Builder bld = Foo.newBuilder();
Descriptors.Descriptor msgDesc = Foo.getDescriptor();
List<Descriptors.FieldDescriptor> fields = msgDesc.getFields();
for (Descriptors.FieldDescriptor field : fields) {
Message.Builder subBld = bld.getFieldBuilder(field);
// set foreign value xyz using subBld
// subBld.setFleld(subfield1, xyz);
}
But for "MsgB b", the same code throws "UnsupportedOperationException: getFieldBuilder() called on a non-Message type."
I understand the repeated field is a list, I may set each one separately. But, how do I get a builder first? Is there a clean and easy way to do the similar?
Thanks for any input.
You don't get a builder for the repeated field itself - you call Builder.addRepeatedField(field, value) etc. To get a builder for the type of the repeated field, you can use:
Builder builder = bld.newBuilderForField(field)
If you want to modify an existing value, you can use Builder.getRepeatedFieldBuilder(field, index).
To create an instance to start with, you can use Builder.newBuilderForField:
Message.Builder subBld = bld.newBuilderForField(field);
// Now modify subBld, then...
bld.addRepeatedField(field, subBld.build());

Join using Hibernate Criteria without using Alias on Restriction

I have an object with 70 attributes. For ease of use I created 2 objects, a 'main' object and a 'details' object, with 1:1 relationship based on an auto-generated integer ID. I had a SEARCH screen that allowed searching on any of the main attributes, for which I build Restriction objects for whatever the user typed in. What was nice was that I did this all through iterating through the fields and building criterion - I didn't need ugly code to specifically handle each of the 30 attributes.
Now they want to search on the details fields as well. My previous screen-field-iterating code works perfectly with no changes (the whole reason for making it 'generic'), however I cannot get the JOIN to work to query on details fields.
class House {
Integer houseID;
String address;
. . .
HouseDetails houseDetails;
}
class HouseDetails {
Integer houseID;
String color;
. . .
}
I tried to create an alias and add it to the criteria :
criteria.createAlias("houseDetails", "houseDetails");
but I get this error :
org.hibernate.QueryException: could not resolve property: color of: House
Here's the thing - I know this would work if I prefix my restrictions with the alias name, but I do NOT want to have to know which table (House or HouseDetails) the field comes from. That would ruin all the automatic looping code and create specific code for each field.
Since SQL can do this as long as the column names are unique :
select * from house, housedetails where house.houseID = housedetails.houseID
and color = 'blue';
I'm wondering how can I get this to work using criteria??
As an aside, but related to this : Is there a way to perform something like Java's introspection on Hibernate HBM.XML mapping files? A number of times I've wanted to do this to solve problems but never found an answer. For the above problem, if I could easily find out which table contained each field, I could add the prefix to the Restriction. Something like this :
// Map of search keys (columns) to searching values
for ( String key : parms.keySet() ) {
String val = parms.get(key);
if ( HIBERNATE-SAYS-KEY-IS-FROM-DETAILS-TABLE ) {
key = "houseDetails." + key;
}
criteria.add(Restrictions.eq(key,val));
}
You can make method to find table name for passed column name.
By using SessionFactory.getClassMetaData() you can get all the information about that class. Once you have ClassMetaData then you can get all the property names. An demo method is shown below:
public String findTableName(String columnName)
{
boolean found=false;
Map<String, ClassMetadata> classMetaData = sessionFactory.getAllClassMetadata();
for (Entry<String, ClassMetadata> metaData : classMetaData.entrySet())
{
String[] propertyNames = metaData.getValue().getPropertyNames();
for (String property : propertyNames)
{
if(property == columnName)
{
return metaData.getKey() + "." + property;
found=true;
break;
}
}
if(found)
break;
}
}
The alias mechanism in hibernate and the Criteria API is pretty well specified. I suggest going through the documentation a little a bit.
I think what you want is something like this:
Criteria criteria = session.createCriteria(House.class);
criteria.createAlias("houseDetails.color", "houseColor");
criteria.add(Restrictions.eq("houseColor", "red"));

Categories