Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add an option to specify properties prefix #100

Closed
alonbl opened this issue Aug 4, 2018 · 15 comments
Closed

Add an option to specify properties prefix #100

alonbl opened this issue Aug 4, 2018 · 15 comments
Labels
Properties Issue related to (Java) Properties format backend
Milestone

Comments

@alonbl
Copy link

alonbl commented Aug 4, 2018

Hi,

Properties may have a prefix for an object, for example:

a.b.c.name =
a.b.c.id =
x.y.z.name =
x.y.z.color =

It would be nice if a prefix can be specified, so that only these properties with the prefix will be loaded, prefix will be stripped and then business as usual. When writing, the prefix will be added.

This will allow reading system properties and complex file properties using this interface quite easily and replace many of the complex properties processing.

If this is acceptable, I can workout a patch.

Thanks!

@dharezlak
Copy link

Can this be configured somehow with the current configuration options? I am interested in writing properties with a common prefix to a file.

@alonbl
Copy link
Author

alonbl commented Aug 21, 2018

I could not find, a workaround:

import com.fasterxml.jackson.annotation.*;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.dataformat.yaml.*;
import java.util.*;

public class T {

     static class Test {
           @JsonProperty
           int field1 = 44;
     }

     public static Object nestObject(Object o, List<String> levels) {
           if (levels.size() == 0) {
                return o;
           }
           else {
                return Collections.singletonMap(levels.get(0), nestObject(o, levels.subList(1, levels.size())));
           }
     }

     public static Object nestObject(Object o, String... levels) {
           return nestObject(o, Arrays.asList(levels));
     }

     public static void main(String... args) throws Exception {
           ObjectMapper mapper = new ObjectMapper(new YAMLFactory());
           System.out.println(mapper.writeValueAsString(nestObject(new Test(), "a", "b", "c")));
     }
}

@dharezlak
Copy link

I successfully used withRootName() for the writing case:

JavaPropsMapper mapper = new JavaPropsMapper();
mapper
	.writerFor(Bean.class)
	.with(JavaPropsSchema
			.emptySchema()
			.withKeyValueSeparator(" = ")
			.withWriteIndexUsingMarkers(true)
			.withFirstArrayOffset(0)
			.withIndexMarker(Markers.create("[", "]")))
	.withRootName("root.subroot")
	.writeValueAsString(bean);

@alonbl
Copy link
Author

alonbl commented Aug 21, 2018

Nice, I need it mostly for reading. Of course I can read into Map<String, Object> and then convert value the value of the nested object, however, I believe this feature can be very useful.

@cowtowncoder cowtowncoder changed the title (properties) add an option to specify properties prefix Add an option to specify properties prefix Aug 31, 2018
@cowtowncoder cowtowncoder added the Properties Issue related to (Java) Properties format backend label Aug 31, 2018
@cowtowncoder
Copy link
Member

This sounds reasonable to me; useful thing. I would be interested in a PR -- ideally against 2.10 branch, since this seems like an incremental feature that need not wait until 3.0.

I could see this working either via reuse of "root name" concept, or, as a new property of JavaPropsSchema.

@alonbl
Copy link
Author

alonbl commented Aug 31, 2018

@cowtowncoder this is a draft as a base for discussion at #105 .

I did not use the withRootName as it seems to me that it should be altered at core to support multiple nodes, for example for json/yaml/properties to have a nested prefix and not a single one, to resolve the problem in a generic manner.

For example, I would expect to be able to produce a yaml at nested level with root prefix ["prefix1", "prefix2", "prefix3"]:

prefix1:
  prefix2:
    prefix3:
       name: Bob 

Please tell me what you think.

@alonbl
Copy link
Author

alonbl commented Sep 19, 2018

Hi @cowtowncoder any chance you review?

@FasterXML FasterXML deleted a comment from linyzh Feb 22, 2019
@cowtowncoder
Copy link
Member

Missed this one earlier, but will add to my WIP page to hopefully review:

https://github.com/FasterXML/jackson-future-ideas/wiki/Jackson-Work-in-Progress

@cowtowncoder
Copy link
Member

@alonbl Apologies for ultra-slow review. I think I would like to (finally!) proceed, and unless I've asked for and received it, would need CLA:

https://github.com/FasterXML/jackson/blob/master/contributor-agreement.pdf

which only needs to be sent once for all contributions. Usual way is to print, fill & sign, scan, email to info at fasterxml dot com.
Once this is done, I can do merge, possible post-cleanup, and this can make it in 2.10.0.

@alonbl
Copy link
Author

alonbl commented May 29, 2019 via email

cowtowncoder pushed a commit that referenced this issue May 31, 2019
Properties may contain multiple objects based on prefix, for example:

    a.b.c.name =
    a.b.c.id =
    x.y.z.name =
    x.y.z.color =

To read these formats a prefix should be used as a filter when reading and as
append when generating.

A new optional JavaPropsSchema::prefix() and JavaPropsSchema::withPrefix() are
added to control the behavior.

As each path component is an object, use of ObjectReader::withRootName has a
different meaning so schema property was used.

PR #100
@cowtowncoder cowtowncoder added this to the 2.10.0 milestone May 31, 2019
cowtowncoder added a commit that referenced this issue May 31, 2019
@mistriel
Copy link

mistriel commented Jun 7, 2020

Nice, I need it mostly for reading. Of course I can read into Map<String, Object> and then convert value the value of the nested object, however, I believe this feature can be very useful.

Still you can use the same trick for reading:

Bean bean = mapper.readerFor(Bean.class)
                    .withRootName("x.y.z")
                    .readValue(inputStream);

@cdprete
Copy link

cdprete commented May 12, 2021

How is this supposed to work exactly?

I've the following:

private static final ObjectMapper objectMapper = new ObjectMapper(new YAMLFactory()).configure(FAIL_ON_UNKNOWN_PROPERTIES, false);

    public static <T> T loadProperties(String prefix, Class<T> clazz, Resource resource) throws IOException {
        Assert.notNull(resource, "The resource to load cannot be null");
        Assert.isTrue(resource.exists() && resource.isReadable(), "The resource to load must exist and it must be readable");

        final ObjectReader reader = readerFor(prefix, clazz);
        final ObjectWriter writer = writerFor(prefix, clazz);

        T value = reader.readValue(resource.getInputStream());
        String yaml = writer.writeValueAsString(value);
        yaml = SystemPropertyUtils.resolvePlaceholders(yaml, true);

        return reader.readValue(yaml);
    }

    private static <T> ObjectReader readerFor(String prefix, Class<T> clazz) {
        ObjectReader reader = objectMapper.readerFor(clazz);
        if(prefix != null && !prefix.isBlank()) {
            reader = reader.withRootName(prefix);
        }

        return reader;
    }

    private static <T>ObjectWriter writerFor(String prefix, Class<T> clazz) {
        ObjectWriter writer = objectMapper.writerFor(clazz);
        if(prefix != null && !prefix.isBlank()) {
            writer = writer.withRootName(prefix);
        }

        return writer;
    }

and when I load, let's say, a file test.yaml with in prefix.foo: bar and using the string prefix as prefix, it fails with:

com.fasterxml.jackson.databind.exc.MismatchedInputException: Root name ('prefix.foo') does not match expected ('prefix') for type `foo.PropertiesLoaderTest$Foo`
 at [Source: (BufferedInputStream); line: 1, column: 1] (through reference chain: foo.PropertiesLoaderTest$Foo["prefix.foo"])

@cowtowncoder
Copy link
Member

@cdprete I am not sure how what you show is in related to this issue -- issues for Java properties format backend, not YAML.

@cdprete
Copy link

cdprete commented May 18, 2021

@cdprete I am not sure how what you show is in related to this issue -- issues for Java properties format backend, not YAML.

Any plan to have it also for YAML files?

@cowtowncoder
Copy link
Member

cowtowncoder commented May 18, 2021

@cdprete I don't think there is a specific plan. I think databind has a request for @JsonWrapped (as reverse of @JsonUnwrapped), see:

FasterXML/jackson-databind#512

which might cover this -- but no work done for that. It is highly voted-for fwtw.

Properties input is bit different as it does not have explicit structure and comes as a sequence of key/value pairs, so applying prefix is easier. There is no theoretical reason why prefix handling could not be added to YAML backend as a one-off, at streaming level (@JsonWrapped would be databind level above).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Properties Issue related to (Java) Properties format backend
Projects
None yet
Development

No branches or pull requests

5 participants