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

Period and Duration aggregate type #487

Merged
merged 8 commits into from
Jul 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

## [0.4.6] - 2023-07-20

### Added

- Adds the `PeriodAndDuration` type to aggregate `Period` and `Duration` serialization

### Changed

- Drops the `getPeriodValue` function in favour of `getPeriodAndDurationValue` in the serialization interface.
- Drops the `writePeriodValue` function in favour of `writePeriodAndDurationValue` in the serialization interface.

## [0.4.5] - 2023-06-27

### Changed
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,19 @@ public ApiException(@Nonnull final Throwable cause) {
@Nonnull
private ResponseHeaders responseHeaders = new ResponseHeaders();

/** Gets the HTTP response headers for the error response */
/**
* Gets the HTTP response headers for the error response
* @return The response headers collections from the failed response.
*/
@Nonnull
public ResponseHeaders getResponseHeaders() {
return new ResponseHeaders(responseHeaders);
}

/** Sets the HTTP response headers for the error response */
/**
* Sets the HTTP response headers for the error response
* @param responseHeaders The response headers collections to set.
*/
public void setResponseHeaders(@Nonnull ResponseHeaders responseHeaders) {
Objects.requireNonNull(responseHeaders);
this.responseHeaders = new ResponseHeaders(responseHeaders);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@
class CaseInsensitiveMap implements Map<String, Set<String>>{
private final HashMap<String, HashSet<String>> internalMap = new HashMap<>();

/**
* Formats the string to lower case
* @param key string to normalize to lower case
* @return The normalized string
*/
protected String normalizeKey(@Nonnull final String key) {
Objects.requireNonNull(key);
return key.toLowerCase(Locale.ROOT);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@

import com.microsoft.kiota.serialization.Parsable;
import com.microsoft.kiota.serialization.ParsableFactory;

/**
* The {@code ResponseHandler} implementation to handle native response objects
*/
public class NativeResponseHandler implements ResponseHandler {
private Object value;
private HashMap<String, ParsableFactory<? extends Parsable>> errorMappings;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,263 @@
package com.microsoft.kiota;

import javax.annotation.Nonnull;
import javax.annotation.concurrent.Immutable;
import java.io.Serializable;
import java.time.Duration;
import java.time.Period;
import java.time.temporal.ChronoUnit;
import java.time.temporal.Temporal;
import java.time.temporal.TemporalAmount;
import java.time.temporal.TemporalUnit;
import java.time.temporal.UnsupportedTemporalTypeException;
import java.util.Collections;
import java.util.Objects;
import java.util.List;
import java.util.Arrays;
import java.util.ArrayList;

import static java.time.temporal.ChronoUnit.YEARS;
import static java.time.temporal.ChronoUnit.MONTHS;
import static java.time.temporal.ChronoUnit.DAYS;
import static java.time.temporal.ChronoUnit.HOURS;
import static java.time.temporal.ChronoUnit.MINUTES;
import static java.time.temporal.ChronoUnit.SECONDS;
import static java.time.temporal.ChronoUnit.NANOS;


/**
* The aggregate type for {@code Period} and {@code Duration }
*/
@Immutable
public final class PeriodAndDuration implements TemporalAmount, Comparable<PeriodAndDuration>, Serializable {

/**
* A constant for a duration of zero.
*/
public static final PeriodAndDuration ZERO = new PeriodAndDuration(Period.ZERO, Duration.ZERO);

/**
* The period.
*/
private final Period period;

/**
* Gets the period section of the type.
* @return the period section
*/
@Nonnull
public Period getPeriod() {
return period;
}

/**
* The duration.
*/
private final Duration duration;
/**
* Gets the duration section of the type.
* @return the duration section
*/
@Nonnull
public Duration getDuration() {
return duration;
}

/**
* Non-public Constructor for PeriodAndDuration
* @param period The {@code Period} component of the aggregate type
* @param duration The {@code Duration } component of the aggregate type
*/
private PeriodAndDuration(@Nonnull Period period, @Nonnull Duration duration) {
Objects.requireNonNull(period, "parameter period cannot be null");
Objects.requireNonNull(duration, "parameter duration cannot be null");
this.period = period;
this.duration = duration;
}

/**
* Creates an instance based on a period and duration.
* @param period the {@code Period}, not null
* @param duration the {@code Duration}, not null
* @return the combined {@code PeriodAndDuration}, not null
*/
@Nonnull
public static PeriodAndDuration of(@Nonnull Period period, @Nonnull Duration duration) {
Objects.requireNonNull(period, "parameter period cannot be null");
Objects.requireNonNull(duration, "parameter duration cannot be null");
return new PeriodAndDuration(period, duration);
}

/**
* Creates an instance based on a period.
* @param period the {@code Period}, not null
* @return the combined {@code PeriodAndDuration}, not null
*/
@Nonnull
public static PeriodAndDuration ofPeriod(@Nonnull Period period) {
Objects.requireNonNull(period, "parameter period cannot be null");
return new PeriodAndDuration(period, Duration.ZERO);
}

/**
* Creates an instance based on a duration.
* @param duration the {@code Duration}, not null
* @return the combined {@code PeriodAndDuration}, not null
*/
@Nonnull
public static PeriodAndDuration ofDuration(@Nonnull Duration duration) {
Objects.requireNonNull(duration, "parameter duration cannot be null");
return new PeriodAndDuration(Period.ZERO, duration);
}

/**
* @param stringValue the {@code String} parse from.
* @return parsed instance of {@code PeriodAndDuration}
*/
@Nonnull
public static PeriodAndDuration parse(@Nonnull String stringValue) {
Objects.requireNonNull(stringValue, "parameter stringValue cannot be null");

if (stringValue.substring(0,3).contains("PT")) {// it is only a duration value as it starts with 'PT', '+PT' or, '-PT'
return PeriodAndDuration.ofDuration(Duration.parse(stringValue));
}
int timePosition = stringValue.indexOf("T");
if (timePosition < 0) {// only a period value as there is no time component
return PeriodAndDuration.ofPeriod(Period.parse(stringValue));
}

String sign = "";
if (stringValue.charAt(0) == '-') {
sign = "-";
}// no need for checking the `+` sign as this is the default

Period period = Period.parse(stringValue.substring(0, timePosition));//sign will be passed and parsed
Duration duration = Duration.parse(sign + "P" + stringValue.substring(timePosition));// pass the negative if need be
return PeriodAndDuration.of(period, duration);
}

/**
* @param periodAndDuration the {@code PeriodAndDuration} for which to compare to
* @return a negative integer, zero, or a positive integer as this object is less than, equal to, or greater than the specified object.
*/
@Override
public int compareTo(@Nonnull PeriodAndDuration periodAndDuration) {
Objects.requireNonNull(periodAndDuration, "parameter periodAndDuration cannot be null");

if(this.equals(periodAndDuration)) {
return 0;//they are the same/equal
}

if(this.period.equals(periodAndDuration.getPeriod())) {// same period so just compare the durations
return this.duration.compareTo(periodAndDuration.getDuration());
}

// just check if the difference in the period is negative as this makes the duration moot
if(this.period.minus(periodAndDuration.getPeriod()).isNegative()) {
return -1;//this period is smaller. So duration won't count
}else {
return 1;
}
}

/**
* @param unit the {@code TemporalUnit} for which to return the value
* @return the long value of the unit
*/
@Override
public long get(@Nonnull TemporalUnit unit) {
Objects.requireNonNull(unit, "parameter unit cannot be null");
if (unit instanceof ChronoUnit) {
switch ((ChronoUnit) unit) {
case YEARS:
return period.getYears();
case MONTHS:
return period.getMonths();
case DAYS:
return period.getDays();
case HOURS:
return duration.toHours() % 24;
case MINUTES:
return duration.toMinutes() % 60;
case SECONDS:
return duration.getSeconds() % 60;
case NANOS:
return duration.getNano();
default:
break;
}
}
throw new UnsupportedTemporalTypeException("Unsupported TemporalUnit of type: " + unit);
}

private static final List<TemporalUnit> UNITS = Collections.unmodifiableList(Arrays.<TemporalUnit>asList(YEARS, MONTHS, DAYS, HOURS, MINUTES, SECONDS, NANOS));
/**
* @return the List of TemporalUnits; not null
*/
@Override
public List<TemporalUnit> getUnits() {
return new ArrayList<>(UNITS);
}

/**
* @param temporal the temporal object to add the amount to, not null
* @return an object of the same observable type with the addition made, not null
*/
@Override
public Temporal addTo(@Nonnull Temporal temporal) {
Objects.requireNonNull(temporal, "parameter temporal cannot be null");
return temporal.plus(period).plus(duration);//just add everything up
}

/**
* @param temporal the temporal object to subtract the amount from, not null
* @return an object of the same observable type with the subtraction made, not null
*/
@Override
public Temporal subtractFrom(@Nonnull Temporal temporal) {
Objects.requireNonNull(temporal, "parameter temporal cannot be null");
return temporal.minus(period).minus(duration);//just subtract everything up
}

/**
* Returns a string representation of the instance in the ISO-8601 format 'PnYnMnDTnHnMnS'.
* @return the period in ISO-8601 string format
*/
@Override
public String toString() {
if (period.isZero()) {
return duration.toString();
}
if (duration.isZero()) {
return period.toString();
}
//simply concatenate and drop the first `P` in the duration
return period + duration.toString().substring(1);
}

/**
* Gets the hashcode for the object.
* @return The hashCode of the object
*/
@Override
public int hashCode() {
return period.hashCode() + duration.hashCode();
}
/**
* Checks if this instance is equal to the specified {@code PeriodAndDuration}.
* @param otherPeriodAndDuration the other Object, null returns false
* @return true if the other otherPeriodAndDuration is equal to this one
*/
@Override
public boolean equals(Object otherPeriodAndDuration) {
if(this == otherPeriodAndDuration) {
return true; // same instance
}

if (otherPeriodAndDuration instanceof PeriodAndDuration) {
PeriodAndDuration otherInstance = (PeriodAndDuration) otherPeriodAndDuration;
return this.period.equals(otherInstance.period) && this.duration.equals(otherInstance.duration);
}
return false;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/*
/**
* This annotation allows mapping between the query parameter name in the template and the property name in the class.
*/
@Retention(RetentionPolicy.RUNTIME)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,11 @@ public class RequestHeaders extends Headers {
public RequestHeaders() {
super();
}

/** Copy constructor */

/**
* Copy constructor
* @param requestHeaders The request headers to initialize with.
*/
public RequestHeaders(@Nonnull RequestHeaders requestHeaders) {
super(requestHeaders);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.OffsetDateTime;
import java.time.Period;


import javax.annotation.Nonnull;
Expand Down Expand Up @@ -305,8 +304,8 @@ else if(valueClass.equals(LocalDate.class))
writer.writeLocalDateValue(null, (LocalDate)value);
else if(valueClass.equals(LocalTime.class))
writer.writeLocalTimeValue(null, (LocalTime)value);
else if(valueClass.equals(Period.class))
writer.writePeriodValue(null, (Period)value);
else if(valueClass.equals(PeriodAndDuration.class))
writer.writePeriodAndDurationValue(null, (PeriodAndDuration)value);
else {
final RuntimeException result = new RuntimeException("unknown type to serialize " + valueClass.getName());
span.recordException(result);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@ public ResponseHeaders() {
super();
}

/** Copy constructor */
/**
* Copy constructor
* @param responseHeaders The response headers to initialize with.
*/
public ResponseHeaders(@Nonnull ResponseHeaders responseHeaders) {
super(responseHeaders);
}
Expand Down
Loading