Skip to content

Commit

Permalink
More complete javadoc
Browse files Browse the repository at this point in the history
  • Loading branch information
dblevins committed Jan 7, 2025
1 parent c2b2d9d commit 33b4d6a
Show file tree
Hide file tree
Showing 2 changed files with 236 additions and 11 deletions.
179 changes: 168 additions & 11 deletions src/main/java/org/tomitribe/pixie/Instance.java
Original file line number Diff line number Diff line change
Expand Up @@ -50,30 +50,46 @@ public Builder(final Class<T> type) {
this(type, "instance");
}

public Builder(final Class<T> type, final String instance) {
public Builder(final Class<T> type, final String name) {
this.type = type;
this.name = instance;
properties.put(name, "new://" + type.getName());
this.name = name;
properties.put(this.name, "new://" + type.getName());
}

/**
* Use of comp(*) and option(*) create the expectation the
* class definition has explicitly declared a need for these
* things via the @Component and @Option annotations.
*
* When no such declaration exists an exception will be thrown
* on build() unless warnOnUnusedProperties() has been called.
*/
public Builder<T> warnOnUnusedProperties() {
warnOnUnusedProperties = true;
return this;
}

/**
* Set a component ref value to the specified object
* Sets the value of an explicitly declared @Component reference
* declared in the class of the instance we are creating.
*
* Internally, Pixie wants the value to be a name and to
* subsequently lookup the specified object by name. To
* work around this, we give the specified object a unique
* name, add the object to Pixie System with that name, and
* then set a reference to that name.
* If the class does not declare a @Component reference with the
* name specified an exception will be thrown unless `warnOnUnusedProperties`
*
* This could be optimized.
* Use add(*) to offer objects that may be useful to the created instance
* but are not known as explicit requirements.
*/
public Builder<T> comp(final String name, final Object value) {
final String refName = name + refs.incrementAndGet();
/*
* Internally, Pixie wants the value to be a name and to
* subsequently lookup the specified object by name. To
* work around this, we give the specified object a unique
* name, add the object to Pixie System with that name, and
* then set a reference to that name.
*
* This could be optimized.
*/
final String refName = "unnamed$" + name + refs.incrementAndGet();
properties.put(this.name + "." + name, "@" + refName);
objects.put(refName, value);
return this;
Expand All @@ -84,61 +100,202 @@ public Builder<T> comp(final String name, final String refName) {
return this;
}

/**
* Adds an object to be possibly consumed by the created instance.
*
* Calling this method does not create the expectation the created
* instance needs an object of this type and will not result in
* any form of exception or warning.
*
* Use comp(*) to explicitly create an expectation the supplied
* object value must be consumed by the created instance.
*
* As no name is specified for this object it may only be referenced by type
* and adding more objects of the same type will create ambiguity in resolution.
*
* @param value The object instance we anticipate may be useful to the created instance.
*/
public Builder<T> add(final Object value) {
final String name = "unnamed$" + value.getClass().getSimpleName() + refs.incrementAndGet();
objects.put(name, value);
return this;
}

/**
* Adds an object to be possibly consumed by the created instance.
*
* Calling this method does not create the expectation the created
* instance needs an object of this type and will not result in
* any form of exception or warning.
*
* Use comp(*) to explicitly create an expectation the supplied
* object value must be consumed by the created instance.
*
* @param name Sets an explicit name which enables several instance of the same type to exist and be referenced
* @param value The object instance we anticipate may be useful to the created instance.
*/
public Builder<T> add(final String name, final Object value) {
objects.put(name, value);
return this;
}

/**
* Sets the value of an explicitly declared @Option reference
* declared in the class of the instance we are creating.
*
* If the class does not declare a @Option reference with the
* name specified an exception will be thrown unless `warnOnUnusedProperties`
*
* Use add(*) to offer objects that may be useful to the created instance
* but are not known as explicit requirements.
*/
public Builder<T> option(final String name, final String value) {
properties.put(this.name + "." + name, value);
return this;
}

/**
* Sets the value of an explicitly declared @Option reference
* declared in the class of the instance we are creating.
*
* If the class does not declare a @Option reference with the
* name specified an exception will be thrown unless `warnOnUnusedProperties`
*
* Use add(*) to offer objects that may be useful to the created instance
* but are not known as explicit requirements.
*/
public Builder<T> option(final String name, final Integer value) {
properties.put(this.name + "." + name, value);
return this;
}

/**
* Sets the value of an explicitly declared @Option reference
* declared in the class of the instance we are creating.
*
* If the class does not declare a @Option reference with the
* name specified an exception will be thrown unless `warnOnUnusedProperties`
*
* Use add(*) to offer objects that may be useful to the created instance
* but are not known as explicit requirements.
*/
public Builder<T> option(final String name, final Boolean value) {
properties.put(this.name + "." + name, value);
return this;
}

/**
* Sets the value of an explicitly declared @Option reference
* declared in the class of the instance we are creating.
*
* If the class does not declare a @Option reference with the
* name specified an exception will be thrown unless `warnOnUnusedProperties`
*
* Use add(*) to offer objects that may be useful to the created instance
* but are not known as explicit requirements.
*/
public Builder<T> option(final String name, final Double value) {
properties.put(this.name + "." + name, value);
return this;
}

/**
* Sets the value of an explicitly declared @Option reference
* declared in the class of the instance we are creating.
*
* If the class does not declare a @Option reference with the
* name specified an exception will be thrown unless `warnOnUnusedProperties`
*
* Use add(*) to offer objects that may be useful to the created instance
* but are not known as explicit requirements.
*/
public Builder<T> option(final String name, final Float value) {
properties.put(this.name + "." + name, value);
return this;
}

/**
* Sets the value of an explicitly declared @Option reference
* declared in the class of the instance we are creating.
*
* If the class does not declare a @Option reference with the
* name specified an exception will be thrown unless `warnOnUnusedProperties`
*
* Use add(*) to offer objects that may be useful to the created instance
* but are not known as explicit requirements.
*/
public Builder<T> option(final String name, final Long value) {
properties.put(this.name + "." + name, value);
return this;
}

/**
* Sets the value of an explicitly declared @Option reference
* declared in the class of the instance we are creating.
*
* If the class does not declare a @Option reference with the
* name specified an exception will be thrown unless `warnOnUnusedProperties`
*
* Use add(*) to offer objects that may be useful to the created instance
* but are not known as explicit requirements.
*/
public Builder<T> option(final String name, final Short value) {
properties.put(this.name + "." + name, value);
return this;
}

/**
* Sets the value of an explicitly declared @Option reference
* declared in the class of the instance we are creating.
*
* If the class does not declare a @Option reference with the
* name specified an exception will be thrown unless `warnOnUnusedProperties`
*
* Use add(*) to offer objects that may be useful to the created instance
* but are not known as explicit requirements.
*/
public Builder<T> option(final String name, final Byte value) {
properties.put(this.name + "." + name, value);
return this;
}

/**
* Sets the value of an explicitly declared @Option reference
* declared in the class of the instance we are creating.
*
* If the class does not declare a @Option reference with the
* name specified an exception will be thrown unless `warnOnUnusedProperties`
*
* Use add(*) to offer objects that may be useful to the created instance
* but are not known as explicit requirements.
*/
public Builder<T> option(final String name, final Character value) {
properties.put(this.name + "." + name, value);
return this;
}

/**
* Sets the value of an explicitly declared @Option reference
* declared in the class of the instance we are creating.
*
* If the class does not declare a @Option reference with the
* name specified an exception will be thrown unless `warnOnUnusedProperties`
*
* Use add(*) to offer objects that may be useful to the created instance
* but are not known as explicit requirements.
*/
public <E extends Enum<E>> Builder<T> option(final String name, final E value) {
properties.put(this.name + "." + name, value);
return this;
}

/**
*
* Creates and returns a new instance of the class specified in the build() method
* using the values supplied to the builder
* @return a new instance of the class specified in the build() method
* @throws org.tomitribe.pixie.comp.ComponentException if the instance cannot be constructed
*/
public T build() {
final System system = new System(warnOnUnusedProperties);
for (final Map.Entry<String, Object> entry : objects.entrySet()) {
Expand Down
68 changes: 68 additions & 0 deletions src/test/java/org/tomitribe/pixie/InstanceBuilderTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

import org.junit.Test;
import org.tomitribe.pixie.comp.Component;
import org.tomitribe.pixie.comp.ConstructionFailedException;
import org.tomitribe.pixie.comp.Default;
import org.tomitribe.pixie.comp.Name;
import org.tomitribe.pixie.comp.Nullable;
Expand Down Expand Up @@ -111,6 +112,10 @@ public void componentRefByType() throws Exception {

}

/**
* Specify the value of the objects @Name parameter via passing
* it in via the builder(class, string) method
*/
@Test
public void name() throws Exception {

Expand All @@ -133,6 +138,10 @@ public void name() throws Exception {

}

/**
* Do not specify the component name for our reference to Address.
* Let the system resolve a valid value by type alone
*/
@Test
public void typeRef() throws Exception {

Expand All @@ -154,6 +163,65 @@ public void typeRef() throws Exception {
assertEquals("USA", address.getCountry());
}

/**
* Do not specify a name for the Address instance we add AND
* Do not specify the component name for our reference to Address.
*/
@Test
public void unamedTypeRef() throws Exception {

final Person person = Instance.builder(Person.class)
.option("age", "37")
.add(new Address("820 Roosevelt Street", "River Falls", State.WI, 54022, "USA"))
.build();

assertNotNull(person);
assertEquals("instance", person.getName());
assertEquals(37, person.getAge().intValue());

final Address address = person.getAddress();
assertNotNull(address);
assertEquals("820 Roosevelt Street", address.getStreet());
assertEquals("River Falls", address.getCity());
assertEquals(State.WI, address.getState());
assertEquals(54022, address.getZipcode());
assertEquals("USA", address.getCountry());
}

@Test(expected = ConstructionFailedException.class)
public void failOnUnusedProperties() throws Exception {

Instance.builder(Person.class)
.option("age", "37")
.option("height", "70")
.add("address", new Address("820 Roosevelt Street", "River Falls", State.WI, 54022, "USA"))
.build();

}

@Test
public void warnOnUnusedProperties() throws Exception {

final Person person = Instance.builder(Person.class)
.warnOnUnusedProperties()
.option("age", "37")
.option("height", "70")
.add("address", new Address("820 Roosevelt Street", "River Falls", State.WI, 54022, "USA"))
.build();

assertNotNull(person);
assertEquals("instance", person.getName());
assertEquals(37, person.getAge().intValue());

final Address address = person.getAddress();
assertNotNull(address);
assertEquals("820 Roosevelt Street", address.getStreet());
assertEquals("River Falls", address.getCity());
assertEquals(State.WI, address.getState());
assertEquals(54022, address.getZipcode());
assertEquals("USA", address.getCountry());
}

public static class Person {

private final String name;
Expand Down

0 comments on commit 33b4d6a

Please sign in to comment.